[把你的理性思维慢慢变成条件反射]
本文,我们讲介绍访问者模式,文章主题结构与上文一致。惯例,先来看看我们示例工程的环境:
操作系统:win7 x64
其他软件:eclipse mars,jdk8
-------------------------------------------------------------------------------------------------------------------------------------
经典问题:
针对同一个对象,不同接受者对其采用不同的处理方式。如,同一张单据的不同人员,采用不同的处理过程。
思路分析:
要点一:不同对象可以访问该对象,增加新的状态信息,但不可修改原始信息。
要点二:必须显式或隐式的判断出当前使用该对象的处理对象,同时应易于维与扩展。
示例工程:
创建ConcreteElementA.java,ConcreteElementB.java文件,具体内容如下:
package com.yonyou.iuap.gof_Visitor.one;
public class ConcreteElementA extends Element{
@Override
public void accept(Visitor visitor) {
visitor.visitorConcreteElementA(this);
}
}
创建ConcreteVisitorA.java,ConcreteVisitorB.java文件,具体内容如下:
package com.yonyou.iuap.gof_Visitor.one;
public class ConcreteVisitorA extends Visitor{
@Override
public void visitorConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println(concreteElementA.getClass().getName()+"被"+this.getClass().getName()+"访问");
}
@Override
public void visitorConcreteElementB(ConcreteElementB concreteElementA) {
System.out.println(concreteElementA.getClass().getName()+"被"+this.getClass().getName()+"访问");
}
}
创建Element.java文件,具体内容如下:
package com.yonyou.iuap.gof_Visitor.one;
public abstract class Element {
public abstract void accept(Visitor visitor);
}
创建ObjectStructure.java文件,具体内容如下:
package com.yonyou.iuap.gof_Visitor.one;
import java.util.ArrayList;
import java.util.List;
public class ObjectStructure {
private List<Element> elements = new ArrayList<Element>();
public void attach(Element element){
elements.add(element);
}
public void detach(Element element){
elements.remove(element);
}
public void accept(Visitor visitor){
for(Element e:elements){
e.accept(visitor);
}
}
}
创建Visitor.java文件,具体内容如下:
package com.yonyou.iuap.gof_Visitor.one;
public abstract class Visitor {
public abstract void visitorConcreteElementA(ConcreteElementA concreteElementA);
public abstract void visitorConcreteElementB(ConcreteElementB concreteElementA);
}
创建Window.java文件,具体内容如下:
package com.yonyou.iuap.gof_Visitor.one;
public class Window {
public static void main(String[] args) {
ObjectStructure o = new ObjectStructure();
o.attach(new ConcreteElementA());
o.attach(new ConcreteElementB());
ConcreteVisitorA v1 = new ConcreteVisitorA();
ConcreteVisitorB v2 = new ConcreteVisitorB();
o.accept(v1);
o.accept(v2);
}
}
【上面的代码直接看的话,可能有难度。先把代码提供给各位看官是希望现将代码运行起来,观察结果。下面我们介绍相关的概念与原理】
模式总结:
访问者模式结构图:
访问者模式:
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下,定义作用于这些元素的新操作。组成部分:
- Visitor(抽象访问者):抽象访问者为对象结构中的每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚的知道访问的具体元素的类型,ConcreteElement需要实现这些操作方法,定义对这些元素的访问操作。
- ConcreteVisitor(具体访问者):具体访问者实现了每个由Visitor声明的操作,每一个操作用于访问对象结构中一种类型的元素。
- Element(抽象元素):抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法通常以一个抽象访问者作为参数。
- ConcreteElement(具体元素):具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对一个元素的操作。
- ObjectStructure(对象结构):对象结构是一个元素的集合,它用于存放元素对象,并且提供了遍历其内部的方法。它可以结合组合模式来实现,也可以是一个简单的集合对象。
在访问者模式中,包括了两个层次结构:
- 一个是访问者层次结构,提供了抽象访问者和具体访问者。
- 一个是元素层次结构,提供了抽象元素和具体元素。
相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同访问者以不同的访问方式访问。这种方式有助于在不修改原有系统的条件下,为新增访问者与元素提供便利。
关于Visitor中的方法命名问题:
一般情况下,可以直接使用visit+ConcreteElementA(ElementA eA)的方式命名。另外,也可以通过重载的方式直接使用visit()方法。
关于Element中的方法命名问题:
一般情况下,其中定义了一个accept(Visitor visitor)方法,其参数类型是一个抽象访问者。在运行时,由具体的ConcreteElement动态决定,并且在其中调用visitor的visit*方法。示例代码请参考上文。
在ConcreteElement类中的accept方法,通过调用Visitor类的visitor*方法实现对元素的访问,并以当前对象作为visitor*()方法的参数。具体执行过程如下:
- 调用ConcreteElement类的accept方法,并将Visitor作为参数。
- 在ConcreteElement类accept方法内部传入当前ConcreteElement对象(this)
- 执行Visitor对象的visitor*()方法,在其中还可以调用ConcreteElement的业务方法。
反思:
应用场景:
- 适用于数据结构相对稳定,算法结构容易变化系统。
- 一个对象结构包含多个类型的对象,希望根据这些对象类型的不同采用不同的操作。
- 一个对象的操作需要新增处理过程,避免污染原有的处理类时。访问者模式可以实现对象数据结构与访问操作的分离。
优点:
- 新增或修改访问操作非常方便,符合“开闭原则”
- 将Element的访问行为集中到一个Visitor对象内部,使得其职责更加清晰,利于复用。
缺点:
- 对于新增Element类的步骤较为复杂,需要新增一个新的抽象操作,并在ConcreteVisitor中增加具体操作。
- 对于从外部访问Element元素,需要其开放部分接口,由此破坏了其封装性。
-------------------------------------------------------------------------------------------------------------------------------------
至此,被说了很多遍的设计模式---访问者模式 结束
特别备注:
访问者模式是一个使用频率较低的设计模式。在此,仅作为学习档案记录下来,以备不时之需。各位看官如果对此模式有深入了解的需求,建议寻找更为详尽的学习资料查阅。
参考资料:
图书:《大话设计模式》
其他博文:http://blog.csdn.NET/lovelion/article/details/7563445