概念:
访问者模式(Visitor pattern)是一种行为型设计模式,它允许在不修改已有对象结构的情况下定义新操作。该模式将数据结构与操作分离,使得新增操作变得容易,并且可以在不同的数据结构上复用相同的操作。
特点:
- 将操作封装到独立的访问者类中,使得添加新的操作变得简单。
- 可以对一个对象结构中的元素进行多种不同类型的遍历和处理。
- 访问者模式通过双重分派来实现动态绑定,即运行时根据具体元素类型调用对应访问者方法。
优点:
- 增加新的具体访问者或元素类都比较容易扩展,符合开闭原则。
- 将相关行为集中到一个类中,提高代码可维护性和可读性。
- 具体元素类无需关心如何执行具体操作逻辑,只需要接受访问者并调用自身方法即可。
缺点:
- 增加新元素会涉及所有具体访问者类进行修改,在存在大量元素和/或具体访问者时可能导致代码改动较大。
- 访问者模式增加了系统复杂度,并且可能降低运行效率。
适用场景:
- 需要对一个复杂对象结构中的元素进行不同类型的操作,而又不希望这些操作污染元素类。
- 需要在运行时动态添加新的操作,且这些操作可能是不断变化的。
- 对象结构稳定,但经常需要定义新的操作。
实现方式:
- 增加新的具体访问者或元素类都比较容易扩展,符合开闭原则。
- 将相关行为集中到一个类中,提高代码可维护性和可读性。
- 具体元素类无需关心如何执行具体操作逻辑,只需要接受访问者并调用自身方法即可。
缺点:
- 增加新元素会涉及所有具体访问者类进行修改,在存在大量元素和/或具体访问者时可能导致代码改动较大。
- 访问者模式增加了系统复杂度,并且可能降低运行效率。
适用场景:
- 需要对一个复杂对象结构中的元素进行不同类型的操作,而又不希望这些操作污染元素类。
- 需要在运行时动态添加新的操作,且这些操作可能是不断变化的。
- 对象结构稳定,但经常需要定义新的操作。
实现方式:
- 需要对一个复杂对象结构中的元素进行不同类型的操作,而又不希望这些操作污染元素类。
- 需要在运行时动态添加新的操作,且这些操作可能是不断变化的。
- 对象结构稳定,但经常需要定义新的操作。
实现方式:
通过将访问者对象传递给元素类,在元素类内部根据具体访问者类型调用对应方法。此方式只有一次动态绑定。
实现原理:
- 定义访问者接口(Visitor):该接口声明了多个重载方法,每个方法对应一个具体元素类,并且传入具体元素对象作为参数。
- 定义具体访问者类(ConcreteVisitor):实现了访问者接口,在每个visit方法中根据传入的具体元素类型进行相应操作。
- 定义抽象元素类(Element):声明accept方法,用于接受访问者对象并调用其visit方法。
- 定义具体元素类(ElementA和ElementB):继承自抽象元素类,实现accept方法,在其中将自身作为参数调用访问者对象的visit方法。
实现代码:
interface Visitor {
void visit(ElementA element);
void visit(ElementB element);
}
class ConcreteVisitor implements Visitor {
@Override
public void visit(ElementA element) {
// 对ElementA进行操作逻辑
System.out.println("Visiting Element A");
}
@Override
public void visit(ElementB element) {
// 对ElementB进行操作逻辑
System.out.println("Visiting Element B");
}
}
abstract class Element {
public abstract void accept(Visitor visitor);
}
class ElementA extends Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class ElementB extends Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Main {
public static void main(String[] args) {
Element elementA = new ElementA();
Element elementB = new ElementB();
Visitor visitor = new ConcreteVisitor();
elementA.accept(visitor); // 调用ElementA的accept方法,并传入visitor对象
elementB.accept(visitor); // 调用ElementB的accept方法,并传入visitor对象
}
}
存在问题:
单分派方式的实现原理相对简单,但它有一个明显的缺点:每次新增具体元素类时,都需要在访问者接口和具体访问者类中添加对应的visit方法。这样会导致具体访问者类和抽象元素类之间的耦合增加,当元素和操作数量庞大时,维护起来可能会比较困难。文章来源:https://uudwc.com/A/12BZz
另外,在单分派方式下,动态绑定只发生一次,即在调用accept方法时根据具体元素类型选择合适的visit方法。因此,在运行时无法根据不同操作类型再进行动态绑定。文章来源地址https://uudwc.com/A/12BZz