意图
表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。
结构
- Visitor(访问者)为该对象结构中ConcreteElement(具体元素)的每一个类声明一个Visit操作,该操作的名字和特征标识了发送Visit请求给该访问者的那个类,这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
- ConcreteVisitor(具体访问者)实现每个有Visitor声明的操作,每个操作实现本算法的一部分,而算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累计结果。
- Element(元素)定义以一个访问者为参数的Accept操作。
- ConcreteElement(具体元素)实现以一个访问者为参数的Accept操作。
- ObjectStructure(对象结构)能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个组合或者是一个集合,如一个列表或一个无序集合。
适用性
- 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而又想要避免这些操作污染这些对象的类,Visitor使得用户可以将相关的操作集中起来定义再一个类中。当该对象结构被很多应用共享是,用Visitor模式让每个应用仅包含需要用到的操作。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对独有访问者的接口,这可能需要很大的代价。如果对象结构经常改变,那么可能还是在这些类中定义这些操作较好。
代码示例
// Element接口
interface Element {
void accept(Visitor visitor);
}
// ConcreteElement具体元素类
class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
}
class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
}
// Visitor访问者接口
interface Visitor {
void visitConcreteElementA(ConcreteElementA element);
void visitConcreteElementB(ConcreteElementB element);
}
// ConcreteVisitor具体访问者类
class ConcreteVisitor implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println("访问者正在访问 ConcreteElementA");
}
@Override
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println("访问者正在访问 ConcreteElementB");
}
}
// ObjectStructure对象结构类
class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void addElement(Element element) {
elements.add(element);
}
public void removeElement(Element element) {
elements.remove(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
// 示例用法
public class VisitorPatternExample {
public static void main(String[] args) {
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.addElement(new ConcreteElementA());
objectStructure.addElement(new ConcreteElementB());
Visitor visitor = new ConcreteVisitor();
objectStructure.accept(visitor);
}
}
-
Element(元素)接口定义了一个接受访问者的方法
accept(Visitor visitor)
,该方法允许访问者访问元素。 -
ConcreteElementA 和 ConcreteElementB 是具体元素类,它们实现了 Element 接口,并在
accept
方法中调用访问者的相应方法,将自身作为参数传递给访问者。 -
Visitor(访问者)接口声明了访问具体元素的方法,例如
visitConcreteElementA
和visitConcreteElementB
。 -
ConcreteVisitor(具体访问者)类实现了 Visitor 接口,提供了对具体元素的访问方法的具体实现。
-
ObjectStructure(对象结构)类维护了一个元素列表,并提供了一个接受访问者的方法
accept
,在该方法中遍历元素列表,调用每个元素的accept
方法,让访问者访问每个元素。