访问者模式
访问者模式定义了一种在不改变对象结构的前提下,对对象中的元素进行操作的方法。访问者模式将数据结构和数据操作分离,使得数据结构可以在不改变的情况下增加新的操作。
结构
访问者模式示意图
访问者模式将判断类对应的行为交给了被访问的对象(元素,Element)。元素对象调用 访问者对象(访问者,Visitor)中与自己类型对应的访问方法,而在访问方法中又反过来调用元素对象的方法以实现具体逻辑。
应用场景
- 当需要对一个复杂对象结构(例如对象树)中的所有元素执行某些操作,而这些元素所需要进行的操作又不完全一致时
- 当某个行为仅在类层次结构中的一些类中有意义, 而在其他类中没有意义时
优缺点
优点
- 单一职责原则:访问者模式将访问行为从元素类中分离出来,使得元素类只需关注自身的业务逻辑
- 开闭原则:可以引入在不同类对象上执行的新行为,且无需对这些类做出修改。
缺点
- 每当元素增加一个子类时,必须更新所有访问者类
代码示例
下面结合了图形(Shape)的例子展示了访问者模式的实现。
Shape 是一个元素接口,它定义了一个 accept 方法,该方法接受一个访问者对象作为参数。Dot, Circle, 和 Rectangle 是具体的元素类,它们实现了 accept 方法。
Visitor 是访问者接口,它为每种具体的元素类型(Dot, Circle, Rectangle)都声明了一个 visit 方法。XMLExportVisitor 和 DrawVisitor 是具体的访问者类,它们为不同的操作(导出为 XML 和绘图)提供了具体的实现。
关键的交互在于双重分派:
- 客户端代码调用一个元素(如
Circle)的accept方法,并将一个访问者(如XMLExportVisitor)传递给它。 Circle的accept方法会立即调用访问者的visit_circle方法,并将自己(self)作为参数传回。
这样,访问者就能知道它正在访问的是一个 Circle 对象,并执行相应的操作。这种模式允许我们在不修改 Shape 类层次结构的情况下,添加新的操作(只需创建一个新的访问者类),从而将数据结构(Shape)与作用于其上的操作(Visitor)解耦。
备注
这里为 visit_file 和 visit_directory 扩展参数 parent,以便在访问文件时能够知道其父目录,从而通过参数构造出的隐式栈实现打印文件绝对路径。