引用百科
访问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式。据《大话设计模式》中说算是最复杂也是最难以理解的一种模式了。
定义(源于GoF《Design Pattern》):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
从定义可以看出结构对象是使用访问者模式必备条件,而且这个结构对象必须存在遍历自身各个对象的方法。这便类似于Java语言当中的collection概念了。
相关角色
1.抽象访问者Visitor:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法中的参数定义哪些对象是可以被访问的。
2.具体访问者ConcreteVisitor.:实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。
3.抽象元素类Element:接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。抽象元素一般有两类方法,一部分是本身的业务逻辑,另外就是允许接收哪类访问者来访问。
4.具体元素类ObjectStructure:实现抽象元素类所声明的accept方法,通常都是visitor.visit(this),基本上已经形成一种定式了。
结构对象:一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中一般很少抽象出这个角色。
具体实现
相关代码
1、抽象元素类
//抽象元素类
public abstract class AbstractElement {
// 接收访问者访问
public abstract void accept(IVisitor visitor);
// 本身的业务逻辑
public abstract void doSomething();
}
2、元素具体实现类
//元素具体实现类A
public class ConcreteElementA extends AbstractElement {
// 本身的业务逻辑
public void doSomething() {
System.out.println("这是元素1");
}
// 接收访问者访问
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
//元素具体实现B
public class ConcreteElementB extends AbstractElement {
// 本身的业务逻辑
public void doSomething() {
System.out.println("这是元素2");
}
// 接收访问者访问
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
3、访问者接口
//访问者接口
public interface IVisitor {
public void visit(AbstractElement element);
}
4、具体访问者
//访问者具体实现
public class RealVisitor implements IVisitor {
public void visit(AbstractElement element) {
element.doSomething();
}
}
5、结构对象角色
//结构对象角色
class ObjectStruture {
// 仿造测试元素数据
public static List<AbstractElement> getList() {
List<AbstractElement> list = new ArrayList<AbstractElement>();
list.add(new ConcreteElementA());
list.add(new ConcreteElementB());
return list;
}
}
6、客户端Client测试
public class Client {
public static void main(String[] args) {
List<AbstractElement> list = ObjectStruture.getList();
for (AbstractElement e : list) {
// 添加访问者
e.accept(new RealVisitor());
}
}
}
以上代码简单实现了观察者模式,运行输出:
这是元素1
这是元素2
观察者模式优缺点
优点
1)符合单一职责原则:凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。
2)扩展性良好:元素类可以通过接受不同的访问者来实现对不同操作的扩展。
缺点
1)对象结构变化很困难
不适用于对象结构中的类经常变化的情况,因为对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。
2)破坏封装
访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。
适用情况
1) 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
2) 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor模式使得你可以将相关的操作集中起来 定义在一个类中。
3) 当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
4)定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。