java之访问者模式


访问者模式

定义

封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

角色

  1. 抽象访问者(Visitor)角色:声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口。
  2. 具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
  3. 抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参数。
  4. 具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。
  5. 结构对象(ObjectStructure)角色:有如下的责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如List或Set。

示例

以两个节点为例,visitor需要两个方法分别访问两个节点

public interface Visitor {
    public void visit(NodeA node);
    public void visit(NodeB node);
}

具体的visitorA访问拿到具体的node对象

public class VisitorA implements Visitor{

    @Override
    public void visit(NodeA node) {
        System.out.println("VisitorA访问:"+node.operationA());
    }

    @Override
    public void visit(NodeB node) {
        System.out.println("VisitorA访问:"+node.operationB());
    }
}

node接口,接受visitor访问

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

具体的节点nodeA,接受访问者访问并返回自身对象

public class NodeA implements Node {

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

    public String operationA(){
        return "NodeA";
    }
}

具体的节点nodeB,接受访问者返回自身对象

public class NodeB implements Node {

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

    public String operationB(){
        return "NodeB";
    }
}

拥有节点的聚集对象

public class ObjectStructure {

    private List<Node> nodes;

    public ObjectStructure() {
        this.nodes = new ArrayList<Node>();
    }

    public void addNode(Node node){
        this.nodes.add(node);
    }

    public void deleteNode(Node node){
        this.nodes.remove(node);
    }

    public void action(Visitor visitor){
        for (Node node : nodes) {
            node.accept(visitor);
        }
    }
}

测试类

public class VisitorTest {

    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();

        objectStructure.addNode(new NodeA());
        objectStructure.addNode(new NodeB());

        //提供操作方法让visitor一一访问每个node
        objectStructure.action(new VisitorA());
    }
}

分析

  1. node接口对象accept接受visitor的访问,visitor调用visit方法访问node对象并动态传入具体的node实现类(nodeA,nodeB等),然后对具体的node实现类操作,从而达到不修改原来node集合的数据结构的情况下操作数据,例如这里如果再新增一个节点nodeC,只需要在visitor接口中增加一个对nodeC的访问,然后将nodeC增加到集合中,那么我就可以实现对nodeC的操作;
  2. 假设不用访问者模式,由于集合中存放的是Node接口,往集合中增加接口实现类,之后在想取得具体的实现类是很难实现的,例如上面例子中的objectStructure中存放NodeA跟NodeB对象,从objectStructure取出来全是Node对象不能向下转型成具体的实现类,因此不能针对具体实现类操作,用访问者模式则会动态的访问到子类的重写的方法(其实是实现具体的接口)从而获取到具体的子类实例对象;

优点

  1. 好的扩展性
    能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。

  2. 好的复用性
    可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度。

  3. 分离无关行为
    可以通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。

缺点

  1. 对象结构变化很困难
    不适用于对象结构中的类经常变化的情况,因为对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。

  2. 破坏封装
    访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。


原文链接:https://blog.csdn.net/qq_30325833/article/details/90477669