在一个古老的、被电子设备和程序填满的王国里,所有的程序和设备都各司其职,日复一日地进行着他们预设的任务。然而,随着时间的推移,王国的需要开始变化,旧的程序无法满足新的需求,新的功能需要被引入。但是,要改变这些程序的基本结构非常困难,每次变化都需要巨大的努力和时间。
这时,一个名为“访问者”的智慧法师来到了这个王国。他提出了一个方案,称为“访问者模式”。这个模式允许王国的管理者向程序中添加新的操作,而不需要改变程序本身的结构。法师解释说,通过这种方式,他可以为每一个程序添加特定的“访问”能力,这样每当有新的需求时,只需要引入一个新的访问者,而无需更改程序的内核。
法师首先遇到了一座巨大的数据库堡垒。它原本只能存储和检索数据,但现在需要进行复杂的数据分析。法师引入了一个数据分析访问者,这个访问者能够在不更改数据库结构的情况下,实现复杂的数据处理功能。
接着,法师来到了消息传输系统,这个系统需要增加加密功能以提高安全性。再次,法师引入了一个加密访问者,它在不打扰原有系统运行的前提下,成功地为每条消息添加了加密层。
最后,法师访问了用户界面工厂,这里需要一种方法来支持多种语言,以适应国际化的趋势。法师带来了一个国际化访问者,它可以轻松地为界面添加多语言支持,而不需更改界面本身的代码。
访问者模式(Visitor Pattern)
访问者模式(Visitor Pattern)是一种行为设计模式,允许你向一个对象结构中添加新的操作,而无需改变这些对象的类。它通过将操作逻辑从对象结构中分离出来,使得你可以在不修改这些对象的情况下定义新的操作。
核心组件
- Visitor(访问者):定义一个接口,为每种类型的元素类声明一个访问操作。
- ConcreteVisitor(具体访问者):实现每个访问操作,定义对每个元素的具体处理逻辑。
- Element(元素):定义一个接受访问者的接口。
- ConcreteElement(具体元素):实现接受访问者的操作,其方法体通常都是访问者访问该元素的入口。
- ObjectStructure(对象结构):一个元素的集合,可以遍历其内的所有元素,以供访问者访问。
适用场景
- 操作复杂的对象结构:
- 当一个对象结构包含多种类型的对象,且你希望对这些对象执行一些依赖于其具体类的操作。
- 业务规则要求遍历多个不同的对象:
- 如果你需要对一个复合对象进行很多不同并且不相关的操作,但你不想让这些操作“污染”这些对象的类,使用访问者模式可以将相关的操作集中起来。
实现实例
以计算机硬件结构的维护和信息提取为例,使用访问者模式来区分各硬件部件的操作。
访问者接口(Visitor Interface)
定义了对每个元素类访问的操作。
public interface ComputerPartVisitor {
void visit(Computer computer);
void visit(Mouse mouse);
void visit(Keyboard keyboard);
void visit(Monitor monitor);
}
具体元素类(Concrete Element)
实现接受访问者的方法。
public class Computer implements ComputerPart {
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
}
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
具体访问者(Concrete Visitor)
实现访问者接口,定义对每个元素的具体操作。
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
客户端代码(Client Code)
演示访问者模式的使用。
public class Client {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}
优缺点
优点
- 增加新操作容易:
- 在不修改现有对象结构的情况下,可以很容易地向现有对象结构中添加新操作。
- 集中相关操作:
- 通过将相关操作集中在一个访问者类中,可以改进系统的组织和清晰度。
缺点
- 增加新类困难:
- 如果需要增加一个新的具体元素类,所有的访问者类都需要修改,这可能会带来维护问题。
- 打破封装:
- 访问者假设具体元素类的实现细节是公开的,这可能会破坏对象的封装性。
类图
+------------------+ +----------------+ +-----------------+
| Visitor |<--------| Element |<--------| ConcreteElement|
+------------------+ +----------------+ +-----------------+
| + visit(...) | | + accept(...) | | + accept(...) |
+------------------+ +----------------+ +-----------------+
| |
v v
+----------------+ +-----------------+
| ConcreteVisitor | | ConcreteElement |
+----------------+ +-----------------+
| + visit(...) | | + accept(...) |
+----------------+ +-----------------+
总结
访问者模式允许你将操作添加到对象结构中,而不改变这些对象的类。它特别适用于那些对象结构相对稳定,但其上的操作经常变化的系统。通过这种方式,可以将操作的实现与对象结构分离开,从而增强系统的灵活性和可维护性。