TypechoJoeTheme

IT技术分享

统计

访问者模式(Visitor)——23种设计模式之行为型模式

2016-04-24
/
0 评论
/
667 阅读
/
正在检测是否收录...
04/24

在软件构建过程中,由于需求的改变,某些类 层次结构中常常需要增加新的行为(方法),如果 直接在基类中做这样的更改,将会给子类带来 很繁重的变更负担,甚至破坏原有设计。如何在不改变类层次结构的前提下,在运行 时根据需要透明地为类层次结构上的各个类动 态添加新的操作,从而避免上述问题?

为了把一个操作作用于一个对象结构中,一种做法是 把这个操作分散到每一个节点上,导致系统难以理解、 维护和修改。改进方案是把这样的操作包装到一个独 立的对象(visitor)中。然后在遍历过程中把此对象传 递给被访问的元素。

访问者模式表示一个作用于某对象结构中的各元素的操作。它使 你可以在不改变各元素的类的前提下定义作用于这些 元素的新操作。

一、类图表示

访问者模式涉及到 Visitor(抽象访问者),ConcreteVisitor(具体访问者),Element(抽象元素),ConcreteElement(具体元素),ObjectStructure(对象结构)等角色

  • ①、Visitor(抽象访问者):为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
  • ②、ConcreteVisitor(具体访问者):实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片断乃是对应于结构中对象的类。 ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
  • ③、Element(抽象元素):定义一个Accept操作,它以一个访问者为参数。
  • ④、ConcreteElement(具体元素):实现Accept操作,该操作以一个访问者为参数。
  • ⑤、ObjectStructure(对象结构):能枚举它的元素。可以提供一个高层的接口以允许该访问者访问它的元素。可以是一个复合或是一个集合
    java-visitor-model-1

    二、代码示例

public interface Visitor {
    /**
    * 对应于NodeA的访问操作
    */
    public void visit(NodeA node);
    /**
    * 对应于NodeB的访问操作
    */
    public void visit(NodeB node);
}
public class VisitorA implements Visitor {
    /**
    * 对应于NodeA的访问操作
    */
    @Override
    public void visit(NodeA node) {
        System.out.println(node.operationA());
    }
    /**
    * 对应于NodeB的访问操作
    */
    @Override
    public void visit(NodeB node) {
        System.out.println(node.operationB());
    }

}
public class VisitorB implements Visitor {
    /**
    * 对应于NodeA的访问操作
    */
    @Override
    public void visit(NodeA node) {
        System.out.println(node.operationA());
    }
    /**
    * 对应于NodeB的访问操作
    */
    @Override
    public void visit(NodeB node) {
        System.out.println(node.operationB());
    }

}
public abstract class Node {
    /**
    * 接受操作
    */
    public abstract void accept(Visitor visitor);
}
public class NodeA extends Node{
    /**
    * 接受操作
    */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    /**
    * NodeA特有的方法
    */
    public String operationA(){
        return "NodeA";
    }

}
public class NodeB extends Node{
    /**
    * 接受方法
    */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    /**
    * NodeB特有的方法
    */
    public String operationB(){
        return "NodeB";
    }
}
public class ObjectStructure {

    private List<Node> nodes = new ArrayList<Node>();

    /**
    * 执行方法操作
    */
    public void action(Visitor visitor){

        for(Node node : nodes){
            node.accept(visitor);
        }

    }
    /**
    * 添加一个新元素
    */
    public void add(Node node){
        nodes.add(node);
    }
}
public class Client {

    public static void main(String[] args) {
        //创建一个结构对象
        ObjectStructure os = new ObjectStructure();
        //给结构增加一个节点
        os.add(new NodeA());
        //给结构增加一个节点
        os.add(new NodeB());
        //创建一个访问者
        Visitor visitor = new VisitorA();
        os.action(visitor);
    }

}

三、模式分析

使用Visitor模式,必须定义两个类层次:

  • ①、一个对应于接受操作的元素
  • ②、一个对应于定义对元素的操作的访问者

四、双分派

Double-dispatch 双分派

Accept是一个double-dispatch操作。它的含义决定于 两个类型: Visitor的类型和Element的类型。双分派使得访问者可以对每一个类的元素请求不同的操作。

五、优缺点分析

1、优点

  • ①、访问者模式使得增加行的操作变得很容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者,因此,变得容易
  • ②、访问者模式可以将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。
  • ③、访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。迭代器只能访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模式可以做到这一点。
  • ④、累积状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态累积在自己内部,而不是分散到很多的节点对象中。这是有益于系统维护的优点。

2、缺点

  • ①、增加新的节点类变得困难。每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。
  • ②、破坏封装,常常迫使提供访问元素内部状态的公共操作。访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个队所有节点对象的要求:他们必须暴露一些自己的操作和内部状态。不然,访问者的访问就变得没有意义。由于访问者对象自己会累积访问操作所需的状态,从而使这些状态不在存储在几点对象中,这也是破坏封装的。

    六、模式间关系

  • 1、与组合模式的关系

访问者可以用于对一个由 Composite模式定义的对象结构进行操作

  • 2、与解释器模式的关系

访问者可以用于解释。

七、应用场景

 一个对象结构包含许多对象类,我们想执行一 些依赖于具体类的操作

  • ①、要对一个对象结构中的对象进行很多不同的并且不相关的操作,又不想改变这些对象类
  • ②、应在被访问的类结构非常稳定的情况下使用。换言之,系统很少出现需要加入新节点的情况。
  • ③、访问者模式允许在节点中加入新的方法,相应的仅仅需要在一个新的访问者类中加入此方法,而不需要在每一个访问者类中都加入此方法。
  • ④、很多系统可以按照算法和数据结都分开,也就是说一些对象含有算法,而另一些对象含有数据,接受算法的操作。如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就比较合适。因为访问者模式使得算法操作的增加变得容易。

八、总结

  • ①、访问者模式提供了倾斜的可扩展性设计:方法集合的可扩展性和类集合的不可扩展性。
朗读
赞 · 0
版权属于:

IT技术分享

本文链接:

https://idunso.com/archives/1987/(转载时请注明本文出处及文章链接)