访问者模式
访问者模式定义了一种在不改变对象结构的前提下,对对象中的元素进行操作的方法。访问者模式将数据结构和数据操作分离,使得数据结构可以在不改变的情况下增加新的操作。
结构
访问者模式示意图
访问者模式将判断类对应的行为交给了被访问的对象(元素,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
,以便在访问文件时能够知道其父目录,从而通过参数构造出的隐式栈实现打印文件绝对路径。