visitor-acceptor访问者设计模式笔记

声明: 这种模式产生的原因是主要解决:稳定的数据结构和易变的操作耦合问题。

在Java中, 一个鲜明的例子: 大家都知道, Collection好象是个黑色大染缸, 本来有各种鲜明类型特征的对象一旦放入后, 再取出时, 这些类型信息就消失了(仅仅知道父类型而无法确定具体的子类型). 那么我们势必要用If-Else或Switch这种提交结合instanceof来判断.

访问者模式适用于数据结构(数据结构多采用Composite模式封装)相对稳定的系统,它把数据结构和作用于数据结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。访问者模式实际上是分离了集合中的元素和对这些元素进行的操作。不过使用访问者模式是有前提的, 尽量确保Visitor很少变化, 当数据结构变化时,他的visitor接口及其实现都要改变.

抽象访问者(Visitor)角色: 定义接口, 声明一个或多个访问操作.
具体访问者(ConcreteVisitor)角色: 实现抽象访问者所声明的接口, 也就是抽象访问者所声明的各个访问操作. 类似一个回调委托.
抽象被访问者(Acceptor)角色: 声明一个接受操作, 接受一个访问者对象作为一个参数.
具体被访问者(ConcreteAcceptor)角色: 实现抽象被访问者所规定的接受操作. 一般是容器集合类的元素节点.
对象结构(ObjectStructure)角色: 可以遍历结构中的所有元素, 提供一个接口让访问者对象都可以访问每一个元素.

例子1:

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

public interface Visitor {
    void visit(String str);
    void visit(int i);
    void visit(BigInteger integer);
}

public class Strings implements Acceptor {
    private String value;

    public Strings(String value) {
        this.value = value;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(value);
    }
}

public class Integers implements Acceptor {
    private int value;

    public Integers(int value) {
        this.value = value;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(value);
    }
}

public class BigIntegers implements Acceptor {
    private BigInteger value;

    public BigIntegers(BigInteger value) {
        this.value = value;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(value);
    }
}

public class DefaultVisitor implements Visitor {
    @Override
    public void visit(String str) {
        System.out.println("String -> " + str);
    }

    @Override
    public void visit(int i) {
        System.out.println("int -> " + i);
    }

    @Override
    public void visit(BigInteger integer) {
        System.out.println("BigInteger -> " + integer.toString());
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Acceptor> list = new ArrayList<>();
        list.add(new Strings("66666"));
        list.add(new Integers(3234));
        list.add(new BigIntegers(new BigInteger("232342324")));
        DefaultVisitor visitor = new DefaultVisitor();
        for (Acceptor acceptor : list) {
            acceptor.accept(visitor);
        }
    }
}

例子2:

public interface Acceptor {
    void accept(Visitor visitor);
    String getType();
}

public interface Visitor {
    void visit(Strings str);
    void visit(Integers i);
    void visit(BigIntegers integer);
}

public class Strings implements Acceptor {
    private String value;

    public Strings(String value) {
        this.value = value;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    @Override
    public String getType() {
        return "Strings";
    }

    public String getString() {
        return value;
    }
}

public class Integers implements Acceptor {
    private int value;

    public Integers(int value) {
        this.value = value;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    @Override
    public String getType() {
        return "Integers";
    }

    public int getInteger() {
        return value;
    }
}

public class BigIntegers implements Acceptor {
    private BigInteger value;

    public BigIntegers(BigInteger value) {
        this.value = value;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    @Override
    public String getType() {
        return "BigIntegers";
    }

    public BigInteger getBigInteger() {
        return value;
    }
}

public class VisitorAdapter implements Visitor {
    @Override
    public void visit(Strings str) {
        // no-op
    }

    @Override
    public void visit(Integers i) {
        // empty-implementation
    }

    @Override
    public void visit(BigIntegers integer) {
        // do nothing
    }
}

public class DefaultVisitor extends VisitorAdapter {
    @Override
    public void visit(Strings str) {
        System.out.println(str.getType() + " -> " + str.getString());
    }

    @Override
    public void visit(Integers i) {
        System.out.println(i.getType() + " -> " + i.getInteger());
    }
}

public class BigIntegerVisitor extends VisitorAdapter {
    @Override
    public void visit(BigIntegers i) {
        System.out.println(i.getType() + " -> " + i.getBigInteger());
    }
}

public class ObjectStructure {
    private final List<Acceptor> list = new ArrayList<>();

    public void add(Acceptor acceptor) {
        list.add(acceptor);
    }

    public void remove(Acceptor acceptor) {
        list.remove(acceptor);
    }

    public void visitAll(Visitor visitor) {
        for (Acceptor acceptor : list) {
            acceptor.accept(visitor);
        }
    }
}

public class Client {
    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.add(new Strings("66666"));
        objectStructure.add(new Integers(3234));
        objectStructure.add(new BigIntegers(new BigInteger("232342324")));
        System.out.println("DefaultVisitor-----------------------");
        Visitor visitor = new DefaultVisitor();
        objectStructure.visitAll(visitor);
        System.out.println("BigIntegerVisitor-----------------------");
        visitor = new BigIntegerVisitor();
        objectStructure.visitAll(visitor);
    }
}

仔细比对例1和例2, 通过VisitorAdapter, 能适度减弱访问者的缺陷, 如果没有它, 增加一个被访问者节点, 将影响所有具体访问者.

引用陈词(http://www.cnblogs.com/zhenyulu/articles/79719.html)

面向对象的设计原则中最重要的便是所谓的”开一闭”原则。一个软件系统的设计应当尽量做到对扩展开放,对修改关闭。达到这个原则的途径就是遵循”对变化的封装”的原则。

很多系统可以按照算法和数据结构分开,也就是说一些对象含有算法,而另一些对象含有数据,接受算法的操作。如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易。

反过来,如果这样一个系统的数据结构对象易于变化,经常要有新的数据对象增加进来的话,就不适合使用访问者模式。因为在访问者模式中增加新的节点很困难,要涉及到在抽象访问者和所有的具体访问者中增加新的方法。

之所以备注这篇笔记, 是在研究ANTLR的时候, 突然看明白了visitor模式, 然后我上网查考了很多这方面的博客(已经不记得有多少了), 将有感触的文字拷贝了过来. 除了两个例子, 无原创, 也不指着这个盈利或出名, 如果作者不幸看到, 恰巧又不太高兴, 请直接找我吧, 感谢您的文字!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值