技术开发 频道

深入浅出Java的访问者模式

    
    //客户测试程序
public class BeeAndFlowers extends TestCase {   /*    在这里你能看到访问者模式执行的流程:    首先在客户端先获得一个具体的访问者角色    遍历对象结构    对每一个元素调用accept方法,将具体访问者角色传入    这样就完成了整个过程   */   //对象结构角色在这里才 组装 上   List flowers = new ArrayList();   public BeeAndFlowers() {    for(int i = 0; i < 10; i++)     flowers.add(FlowerGenerator.newFlower());   }   Visitor sval ;   public void test() {    // It’s almost as if I had a function to    // produce a Flower string representation:    //这个地方你可以修改以便使用另外一个具体访问者角色    sval = new StringVal();    Iterator it = flowers.iterator();    while(it.hasNext()) {     ((Flower)it.next()).accept(sval);     System.out.println(sval);    }   }   public static void main(String args[]) {    junit.textui.TestRunner.run(BeeAndFlowers.class);   } }
    四、双重分派 

   
对了,你在上面的例子中体会到双重分派的实现了没有? 

    首先在客户程序中将具体访问者模式作为参数传递给具体元素角色(加亮的地方所示)。这便完成了一次分派。 

    进入具体元素角色后,具体元素角 色调 用作为参数的具体访问者模式中的visitor方法,同时将自己(this)作为参数传递进去。具体访问者模式再根据参数的不同来选择方法来执行(加亮的地方所示)。这便完成了第二次分派。 

    五、优缺点及适用情况 

     先来看下访问者模式的使用能否避免引言中的痛苦。使用了访问者模式以后,对于原来的类层次增加新的操作,仅仅需要实现一个具体访问者角色就可以了,而不必修改整个类层次。而且这样符合“开闭原则”的要求。而且每个具体的访问者角色都对应于一个相关操作,因此如果一个操作的需求有变,那么仅仅修改一个具体访问者角色,而不用改动整个类层次。 

    看来访问者模式确实能够解决我们面临的一些问题。 

    而且由于访问者模式为我们的系统多提供了一层“访问者”,因此我们可以在访问者中添加一些对元素角色的额外操作。 

    但是“开闭原则”的遵循总是片面的。如果系统中的类层次发生了变化,会对访问者模式产生什么样的影响呢?你必须修改访问者角色和每一个具体访问者角色…… 

    看来访问者角色不适合具体元素角色经常发生变化的情况。而且访问者角色要执行与元素角色相关的操作,就必须让元素角色将自己内部属性暴露出来,而在java中就意味着其它的对象也可以访问。这就破坏了元素角色的封装性。而且在访问者模式中,元素与访问者之间能够传递的信息有限,这往往也会限制访问者模式的使用。 

    《设计模式》一书中给出了访问者模式适用的情况: 

    1) 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。 

    2) 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。 

    3) 当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。 

    4) 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。 

    你是否能很好的理解呢? 

    六、总结 

    这是一个巧妙而且复杂的模式,它的使用条件比较苛刻。当系统中存在着固定的数据结构(比如上面的类层次),而有着不同的行为,那么访问者模式也许是个不错的选择。

0
相关文章