访问者模式
定义:表示一个作用于某对象结构中的各元素的操作,它使我们在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
成员: Visitor(抽象访问者)、ConcreteVisitor(具体访问者)、Element(抽象元素)、ConcreteElement(具体元素)、ObjectStructure(对象结构)。
理解: 这种模式所应用的情形在生活中比较常见,比如考完试出了一份成绩单,班主任安排了两个学生,一个学生负责找出所有挂科的同学把他们统计下来并叫到办公室。另一个学生负责计算总分累加后排名前十的同学,给他们发奖学金。
可以看到,成绩单在这里就是一个具体对象,但两个学生对这个对象所采取的的行为却不一样,一个负责找出挂科的同学将他们叫到办公室,一个找到班级排名前十的同学给他们发奖学金。这两个学生就是不同的访问者,他们对相同的对象采取了不同的行为。
面对这类问题,就可以使用访问者模式来解决。
类图如下:
代码实现:
//抽象访问者
public abstract class Visitor{
public abstract void visitA(ConcreteElementA elementA);
public abstract void visitB(ConcreteElementB elementB);
}
//具体访问者一号
public class ConcreteVisitor1 extends Visitor{
public void visitA(ConcreteElementA elementA){
/*一号访问者对A元素的具体操作*/
}
public void visitB(ConcreteElementB elementB){
/*一号访问者对B元素的具体操作*/
}
}
//具体访问者二号
public class ConcreteVisitor2 extends Visitor{
public void visitA(ConcreteElementA elementA){
/*二号访问者对A元素的具体操作*/
}
public void visitB(ConcreteElementB elementB){
/*二号访问者对B元素的具体操作*/
}
}
//抽象元素
public interface Element{
public void accept(Visitor visitor);//访问者访问元素的接口
}
//具体元素A
public class ConcreteElementA implements Element{
...
...
public void accept(Visitor visitor){
visitor.visitA(this);
}
...
...
}
//具体元素B
public class ConcreteElementB implements Element{
...
...
public void accept(Visitor visitor){
visitor.visitB(this);
}
...
...
}
//对象结构
public class ObjectStructure{
private ArrayList list = new ArrayList();
public void accept(Visitor visitor)
{
Iterator i = list.iterator();
while(i.hasNext())
{
((Element)i.next()).accept(visitor);
}
}
public void addElement(Element element)
{
list.add(element);
}
public void removeElement(Element element)
{
list.remove(element);
}
}
以上是该模式所涉及到的所有成员。
这些成员具体的交互如下:
class Client{
public static void main(String []args){
Visitor visitor1, visitor2;
Element elementA,elementB;
ObjectStructure obj = new ObjectStructure();
visitor1 = new ConcreteVisitor1();
visitor2 = new ConcreteVisitor2();
elementA = new ConcreteElementA();
elementB = new ConcreteElementB();
obj.addElement(elementA);
obj.addElement(elementB);
obj.accept(visitor1);
obj.accept(visitor2);
}
}
其实ObjectStructure这个类在逻辑交互中并不重要,只是实现了一个类似于自动化的目标。具体逻辑的交互可以简化为
elementA.accept(visitor1);
可以这样理解,一个访问者1,他要访问一个公司办理相应的业务,他首先要走到这个公司门口让这个公司接受自己进入,即被访问元素要调用accept()方法接受访问者对自己的访问,随后,访问者进入公司就可以用这个公司所提供的的服务办理自己的业务,即进入公司的访问者调用visit()方法,因为访问的内容是其正身处的公司,所以visit()方法的参数应该为this,即visitor.visit(this);
从中也可以发现,该模式对添加新的访问者很友好,但对添加新的具体元素很不友好,因为要为所有的访问者添加操作该元素的方法,不符合开闭原则。