页面加载中...

设计模式—访问者(Visitor)模式

| Java | 0 条评论 | 788浏览

Preface

最近在研究一个框架JSqlParser时,发现该框架使用了一种设计模式——访问者(Visitor)模式。遂在网上找了一下该设计模式相关知识,学习整理。

参考:http://www.cnblogs.com/idior/archive/2005/08/18/217500.html

概述

访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。

第一次这句话时,着实费解。关于对访问者模式的理解,可以先见下面这个例子,而后再看最后的综述。

举个例子

比如:你下午请客喝东西,那么就的考虑好你请的这些人中总会有口味不同,有些人喜欢喝茶,有些人喜欢喝果汁,有人喜欢喝咖啡。你当然只有把这些东西都准备好,尽量准备得全一些。那么来的客人喜欢喝啥就自己拿就是了。

那么我们定义一个基本的访问者操作的接口,反正你也不晓得要来的客人喜欢喝什么,那么就抽象一个Visitor什么都喝。

public interface Water {
    void accept(Visitor visitor);
}

 此外,你得把具体得水准备好了,准备好三样:茶、咖啡、果汁。不同类型的水也许会有各自的一些属性操作等等。

public class CaffeeWater implements Water {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void addSugar(int number){
        System.out.print("添加了"+number+"勺糖");
    }
}
public class ZhangsanVisitor implements  Visitor{
    @Override
    public void visit(TeaWater teaWater) {
        System.out.print("张三只喝茶,");
        String hotTea = teaWater.getHotTea();
        System.out.println("拿了"+hotTea);
    }
    @Override
    public void visit(JuiceWater juiceWater) {
        //不喜欢果汁,什么操作也不做
    }
    @Override
    public void visit(CaffeeWater caffeeWater) {
        //不喜欢咖啡,
    }
}
public class Table {
    //准备好所有要喝的东西
    List waters = new ArrayList<>();
    public void addWater(Water water){
        waters.add(water);
    }
    //招待客人
    public void accept(Visitor visitor){
        for (Water water : waters){
            water.accept(visitor);
        }
    }
}

万事具备,客人来了,我们写个测试方法。准备好茶、咖啡、果汁来招待zhangsan、lisi。

@Test
    public void test01(){
        Table table = new Table();
        table.addWater(new TeaWater());//摆上茶
        table.addWater(new JuiceWater()); //摆上果汁
        table.addWater(new CaffeeWater()); //摆上咖啡
        Visitor zhangsan = new ZhangsanVisitor();
        Visitor lisi = new LisiVisitor();
        System.out.println("张三");
        table.accept(zhangsan);
        System.out.println("李四");
        table.accept(lisi);
    }

运行结果如下:

以上就是一个访问者模式的基本实例。

综述

关于访问者模式的UML图,可参见如下:

根据之前例子,可看到,对于访问者模式而言,两个最重要的角色:

  1. 访问者角色(Visitor):声明了一个或者多个访问操作,也就是说,该访问者需要做哪些操作;
  2. 节点角色(Element): 也就是Water这个接口的,它声明一个接受操作,接受一个访问者对象作为一个参量,也就是说,当访问者到来时,需要怎么做。

针对节点角色于访问者角色的方法可看到,节点角色接收一个访问者对象,并把自己作为变量再传给访问者对象,访问者对象再调用节点对象里的逻辑方法,这种操作过程被称为“双重分派”。

此外,对于Table这个对象,就是访问者模式的结构对象角色(ObjectStructure),它就是用于遍历节点中的所有元素。

可以看出,访问者模式适合于操作相对稳定的结构,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。也就是说,对于一个Visitor,它需要有什么操作,必须要非常清楚。如之前的例子,我招待客人,那么我很清楚,我只有茶、咖啡、果汁这个材料,我也只能拿这三个来招待客人。所以在Visitor方法中,就只有那三个方法。这是访问者模式最重要的一点,也是最有缺陷的一点。 如上个例子:有个人还想喝酒,我还得新增加一个节点类,及Water实现类,那么我还得在Visitor中加入一个方法,改动所有的Visitor的实现类,很明显,这样的效率是非常低下的。

 但是对于增加新的访问者那就非常的简单,如上的例子,无非就是多来一个客人,也就是新增加一个新Visitor实现类。

所以,访问者适用于具体操作能够非常稳定的情景下,能够很容易的拓展访问者(Visitor)。

发表评论

最新评论

    来第一个评论吧!