访问者模式的结构图访问者模式(Visitor),表示一个作用与某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式中的角色:
- Visitor:抽象访问者角色,为该对象结构中 ConcreteElement 的每个类声明一个 visit 操作
- ConcreteVisitor:具体访问者角色,实现每个由 Visitor 声明的操作。每个操作实现算法的一部分,而该算法片段乃是对应于结构中对象的类。
- Element:定义一个 Accept 操作,它以一个访问者为参数。
- ConcreteElement:具体元素,实现 Accept 操作。
- ObjectStructure:结构对象角色,能枚举它的元素,可以提供一个高层的接口以运行访问者访问它的元素。
访问者模式的简单实现
(1)抽象访问者角色
public abstract class Visitor {
public abstract void visitConcreteElementA(ConcreteElementA concreteElementA);
public abstract void visitConcreteElementB(ConcreteElementB concreteElementB);
}
(2)具体访问者角色
public class ConcreteVisitor1 extends Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println("ConcreteElementA被ConcreteVisitor1访问");
}
@Override
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
System.out.println("ConcreteElementB被ConcreteVisitor1访问");
}
}
public class ConcreteVisitor2 extends Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println("ConcreteElementA被ConcreteVisitor2访问");
}
@Override
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
System.out.println("ConcreteElementB被ConcreteVisitor2访问");
}
}
(3)Element 类
public abstract class Element {
public abstract void accept(Visitor visitor);
}
(4)具体元素
public class ConcreteElementA extends Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
public void operationA() {
}
}
public class ConcreteElementB extends Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
public void operationB() {
}
}
(5)结构对象角色
public class ObjectStructure {
private List<Element> elements = new ArrayList<>();
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);
}
}
}
(6)客户端调用
public class Client {
public static void main(String[] args) {
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.attach(new ConcreteElementA());
objectStructure.attach(new ConcreteElementB());
ConcreteVisitor1 concreteVisitor1 = new ConcreteVisitor1();
ConcreteVisitor2 concreteVisitor2 = new ConcreteVisitor2();
objectStructure.accept(concreteVisitor1);
objectStructure.accept(concreteVisitor2);
}
}
(7)输出
ConcreteElementA被ConcreteVisitor1访问
ConcreteElementB被ConcreteVisitor1访问
ConcreteElementA被ConcreteVisitor2访问
ConcreteElementB被ConcreteVisitor2访问
访问者模式的使用场景
使用场景:
一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor模式使得你可以将相关的操作集中起来 定义在一个类中。
当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
访问者模式的优缺点
优点:
符合单一职责原则,凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。
扩展性良好:元素类可以通过接受不同的访问者来实现对不同操作的扩展。
缺点:
过于复杂,真正需要的时候才去采用它。
网友评论