两个小宝的幸福

小宝和小宝从此幸福地生活在一起 ^^

逝者如斯
网志分类
· 所有网志
· 小叮当胡思乱想
· 我是OL小叮当
· 小叮当的回忆
· 小叮当东游西逛
· 未分类
最新评论
搜索本站
友情链接
· 我们的小歪
· 管理我的Blog
·
· 呜呜的blog

订阅 RSS

0016310

歪酷博客


小叮当 @ 2007-11-06 16:00

先说说visitor模式。
网上的文章都在说,对一个Collection中的各个元素进行访问的时候,用很多的if else和instanceof来区分各个对象,并调用其中的方法,这样很不好看。所以创造了visitor模式。我总觉得这个例子相当不好理解。
其实visitor模式要解决的问题是这样的:
有这样一些对象,他们各自持有一些操作(方法),现在需要在一个方法里调用这些对象的操作,但我不知道这些对象的类型,我只知道我要调用它们上面的操作,例如,如果是对象A,那我就调用A.a(); 如果是对象B,那我就调用B.b()。因此,把这些对象定义为Visitable, 我定义为Visitor。这些对象接受我的访问,因此他们都有一个accept()方法,参数就是我。在我的实现里,分别有调用A.a()和B.b()的方法,命名为visitA()和visitB(). 因此,对象A实现Visitable时,就要在accept()里调用我的visitA()。同理,对象B实现Visitable时,就要在accept()里调用我的visitB()。

原来的代码是这样的:
A{
  a();
}

B{
   b();
}

我{
访问他们(X){
  if(x instanceof A){
     ((A)x).a();
  }
  else if(x instanceof B){
     ((B)x).b();
   }
}

之后的代码是这样的。添加两个接口:
Visitable{
   accept(Vistor v);
}

Visitor{
  visitA(A); // 这是因为我知道要访问A或者B。
  visitB(B);
}
原来的3个类变成了上面两个接口的实现类:
A implements Visitable{
  accept(Visitor v){
    v.visitA();
  }
  a();
}
B implements Visitable{
  accept(Visitor v){
    v.visitB();
  }
  b();
}
我 implements Visitor{
  visitA(A){
    A.a();
  }
  visitB(B){
    B.b();
  }
  访问他们(X){
    ((Visitable)X).accept();
  }
}
看着很繁琐吧?只有这个方法“访问他们”得到了简化。。。。但是从编程角度来说,后面的实现虽然代码似乎多了点,但是都很不容易出错,也都体现了OO的思想。

再回到ASM。ASM里最重要的一个类就是ClassVisitor。这是个Visitor。它的具体实现是ClassWriter和ClassAdapter等等。他们负责对Class中的每个元素(Field,Method等)进行访问。那么ASM里的Visitable是什么呢?Visitable就是ClassReader。ClassReader是一个parser,对给定的byte[],它可以把这个byte数组拆分成各个元素。ClassReader.accept()的参数就是ClassVisitor,在accept()中,解析过程被触发,每当解析到给定的元素,就会调用相应的Visitor的方法。

ASM提供的最基本的ClassVisitor,就是ClassWriter和ClassAdapter。
ClassWriter负责生成Class的byte数组。它有两种构造方法:一种只有flag,一种有一个ClassReader作为参数。其实两种没有本质区别,但第二种,用ClassReader作为参数时,constant pool是被copy的,在enhancement主要用来“添加代码”的情况下,可以节省大量的时间。一般bytecode enhancement都是在添加代码,所以很有用。
ClassAdapter是一个空的ClassVisitor,它会把所有的visit方法都delegate到自己所持有的ClassVisitor。而自己持有的这个ClassVisitor是通过构造方法传入的。对于我们自己定义的那些Adapter来说,这是一个方便的父类。

例如SerialVersionUIDAdder的典型用法:
 *   ClassWriter cw = new ClassWriter(...);
 *   ClassVisitor sv = new SerialVersionUIDAdder(cw);
 *   ClassVisitor ca = new MyClassAdapter(sv);
 *   new ClassReader(orginalClass).accept(ca, false);

这段代码,首先生成一个ClassWriter,这是一个Visitor,用来得到最终的byte数组。另一个Visitor就是SerialVersionUIDAdder,它的参数是cw。第三个还是Visitor,MyClassAdapter。这三个Visitor形成了一个链。当ClassReader.accept()以ca作为参数,触发了解析过程的时候,会依次调用ca的各个visit方法。如果MyClassAdapter中override了某个visit方法,就会得到调用。
先略去MyClassAdapter,直接看SerialVersionUIDAdder的话,accept()会调用SerialVersionUIDAdder的各个visit方法,计算SerialVersionUID。SerialVersionUIDAdder本身并不改变class的逻辑,因此所有的visit方法都是delegate给cw,也就是ClassWriter。

在我自己的实现中,由于需要而稍微有点不同:
    ClassReader cr = new ClassReader(classBytes);
    ClassWriter cw = new ClassWriter(cr, 0);
    MyEnhancer enhancer = new MyEnhancer(cw, fn);
    ClassVisitor sv = new SerialVersionUIDAdder(enhancer);
    cr.accept(sv, 0);
当ClassReader.accept()触发解析的时候,首先进行SerialVersionUID的计算,然后visit方法才会delegate给enhancer(这是通过ClassAdapter来实现的,因为SerialVersionUIDAdder是ClassAdapter的子类,构造方法传入的enhancer将作为父类所持有的成员变量)。这样SerialVersionUID就是原来的class所决定的值,而不是enhancer完成之后的值。这就是ASM的有趣的链式结构。

当然最后我没有用到SerialVersionUIDAdder



 
小叮当 @ 2007-10-30 09:23

前一阵子觉得只做yoga实在不能减肥。身体倒是柔软了些。但是我本来柔韧性就不错,那些动作对我来说压力不大。而且yoga总要等上课的时间,很不爽,就开始跑步。每次30分钟左右就能出很多很多汗了。每周2次,也不用等上课,去了就跑,小宝很欢迎的说,因为他总是一下下就弄完了他的器械,以前总要等我,现在不用等了。

第一次跑了3km发现很爽,根本不累;结果一下来发现双腿发抖,赶紧又捶又捏,小宝也帮我放松,第二天果然没什么大事,要是不放松估计就完蛋了。跑步果然满爽的,喜欢。昨天又跑了3km,速度调到7.9.我看以后速度就可以维持在8了,如果出汗不够就把incline调上去一点,时间多跑一点。昨天跑完其实有点饿,但是忍住了没有吃东西,睡觉了,今天早上肚肚瘪瘪的,

算下来跑步也坚持了快一个月了,每周2次,但并没有减掉重量。我有心理准备,因为以前也跑过,也没减。感觉运动减肥一上来就会平台期,坚持下来才有用。决定至少再坚持2个月再看结果。而且我的体重还可以了,主要是腿粗 所以只要能让腿型好一点,体重不在乎了。昨天跑完了做了两下拉伸,以后要多做一点,昨天做的太少了。以后跑完看能不能去体操房拉伸一下,大厅里实在没地方,也不好意思,

yoga也是能减肥的,因为yoga也可以促进体内的循环。主要是时间上限制太多。跑步要痛快一些。不过据说运动减肥容易反弹。我看主要还是管不住嘴的缘故。如果管不住嘴巴,想吃多少吃多少,那无论什么都要反弹的。
平时我吃东西还挺控制的,只有周末不好控制,总是大吃大喝! 他们总是诱惑我!