访问者模式
“访问者模式”通常是指软件开发中的一种设计模式,也叫做“Visitor模式”。它属于行为型设计模式之一,主要用于将数据结构和操作解耦。通过使用访问者模式,可以在不修改数据结构的前提下,定义新的操作。
访问者模式的基本思想是:你有一个包含不同对象的对象结构(例如一个元素集合),而这些对象可能需要不同的操作。通过定义一个访问者(Visitor),你可以将这些操作封装在访问者中,并通过遍历对象结构来执行这些操作。这样做的好处是,如果需要对对象结构中的元素进行新的操作,或扩展现有操作,只需要修改或增加访问者,而不需要更改对象本身。
访问者模式的主要组成部分:
- Visitor(访问者):为不同类型的元素定义一个操作接口。通常,这个接口包含多个方法,每个方法对应一种元素类型。
- ConcreteVisitor(具体访问者):实现Visitor接口,为每种类型的元素实现相应的操作。
- Element(元素):定义一个接受访问者的接口。通常这个接口有一个
accept
方法,接受一个访问者对象。 - ConcreteElement(具体元素):实现Element接口,并在
accept
方法中调用访问者的相应方法。 - ObjectStructure(对象结构):保存元素集合并提供遍历这些元素的方法。
示例
//元素接口
public interface Element {
void accept(Visitor visitor);
}
// 具体元素A
class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
public String operationA() {
return "具体元素A";
}
}
// 具体元素B
class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
public String operationB() {
return "具体元素B";
}
}// 访问者接口
interface Visitor {
void visitConcreteElementA(ConcreteElementA element);
void visitConcreteElementB(ConcreteElementB element);
}
// 具体访问者1
class ConcreteVisitor1 implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println(element.operationA() + " 被 具体访问者1 访问");
}
@Override
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println(element.operationB() + " 被 具体访问者1 访问");
}
}// 具体访问者2
class ConcreteVisitor2 implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println(element.operationA() + " 被 具体访问者2 访问");
}
@Override
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println(element.operationB() + " 被 具体访问者2 访问");
}
}// 对象结构
class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void addElement(Element element) {
elements.add(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
public class TestVisitorPattern {
public static void main(String[] args) {
// 创建对象结构并添加元素
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.addElement(new ConcreteElementA());
objectStructure.addElement(new ConcreteElementB());
// 创建具体访问者
Visitor visitor1 = new ConcreteVisitor1();
Visitor visitor2 = new ConcreteVisitor2();
// 使用访问者访问元素
System.out.println("使用 具体访问者1 访问:");
objectStructure.accept(visitor1);
System.out.println("-----------------------------");
System.out.println("使用 具体访问者2 访问:");
objectStructure.accept(visitor2);
}
}
代码解析:
- Element接口:
- 定义了一个
accept
方法,用于接收一个访问者对象。具体元素类将实现这个接口。
- 定义了一个
- 具体元素类(ConcreteElementA 和 ConcreteElementB):
- 这些类实现了
Element
接口,在accept
方法中,它们将自身作为参数传递给访问者的相应方法。 - 每个具体元素类还有自己的操作方法,比如
operationA()
和operationB()
。
- 这些类实现了
- Visitor接口:
- 定义了访问具体元素的方法,例如
visitConcreteElementA
和visitConcreteElementB
。每个方法都对应一种具体元素类型。
- 定义了访问具体元素的方法,例如
- 具体访问者类(ConcreteVisitor1 和 ConcreteVisitor2):
- 这两个类实现了
Visitor
接口,并在visitConcreteElementA
和visitConcreteElementB
方法中定义了对具体元素的访问逻辑。 - 不同的访问者类可以有不同的实现逻辑。例如,一个访问者可能会打印出某些信息,另一个访问者可能会执行其他操作。
- 这两个类实现了
- 对象结构(ObjectStructure):
- 这个类包含一个元素集合,并提供了向集合中添加元素和接受访问者的方法。
accept
方法用于遍历集合中的每个元素,并对其应用访问者。
- TestVisitorPattern类:
- 这个类是程序的入口点。在
main
方法中,创建了一个对象结构,并添加了两个具体元素(ConcreteElementA
和ConcreteElementB
)。 - 然后,它创建了两个具体访问者(
ConcreteVisitor1
和ConcreteVisitor2
),并分别使用它们访问对象结构中的元素。
- 这个类是程序的入口点。在
执行结果:
程序的执行将打印出访问者访问元素时的操作结果。例如:
css复制代码使用 具体访问者1 访问:
具体元素A 被 具体访问者1 访问
具体元素B 被 具体访问者1 访问
-----------------------------
使用 具体访问者2 访问:
具体元素A 被 具体访问者2 访问
具体元素B 被 具体访问者2 访问
总结
访问者模式的优点:
- 符合单一职责原则:通过将操作分离到访问者中,元素类变得更加简洁。
- 符合开闭原则:可以在不修改元素类的情况下增加新的操作。
访问者模式的缺点:
- 违反依赖倒置原则:访问者模式要求具体元素依赖于具体访问者的接口,这与依赖倒置原则有所冲突。
- 扩展性差:如果需要增加新的元素类型,可能需要对所有访问者进行修改。
访问者模式的适用场景:
- 需要对一个对象结构中的对象执行多种操作。
- 对象结构比较稳定,但操作经常变化的场景。