我读了一本关于访客模式的书。它提供了与oodesign 网站中相同的类图。
它说添加新的 ConcreteElement 类很难。但我不明白为什么。据我了解,Concretevisitor 定义了具体元素必须使用的一组操作。因此,当我添加一个具有我之前定义的相同操作的新元素时,我不需要添加任何东西(只需 ConcreteElement 本身)。如果我添加一个新元素,它没有我之前在访问者中定义的相同操作,我需要添加一个新访问者。但这是我必须在任何设计模式中做的。
我读了一本关于访客模式的书。它提供了与oodesign 网站中相同的类图。
它说添加新的 ConcreteElement 类很难。但我不明白为什么。据我了解,Concretevisitor 定义了具体元素必须使用的一组操作。因此,当我添加一个具有我之前定义的相同操作的新元素时,我不需要添加任何东西(只需 ConcreteElement 本身)。如果我添加一个新元素,它没有我之前在访问者中定义的相同操作,我需要添加一个新访问者。但这是我必须在任何设计模式中做的。
好吧,您必须扩展所有访问者。
您有一个调用者,一些需要访问的元素,以及一个元素 - 访问者 - 对各个元素进行处理。您的目标是保持元素和调用者的实现固定,并通过新访问者扩展功能。
通常你有很多具体的访客。如果添加要处理的新元素类型,则需要更改所有具体访问者以考虑到这一点。
为什么?
好吧,假设调用者是“Factory”,并且您有元素“Car”和“Bike”。
对于“油漆”操作,您必须拥有方法
void process(Car c); // Paint a car
void process(Bike b); // Paint a bike
对于“组装”、“包装”、“清洗”等操作也是如此。
如果添加元素“Scooter”,则必须使用新方法扩展所有操作
void process(Scooter s); // Handle a Scooter
这有点工作。此外,您可能会遇到您添加的元素与其他元素如此不同的问题,以至于您无法轻松地将它们适合操作。
维基百科(http://en.wikipedia.org/wiki/Visitor_pattern)说
本质上,访问者允许在不修改类本身的情况下向类族中添加新的虚函数;相反,我们创建了一个访问者类,它实现了虚函数的所有适当的特化。访问者将实例引用作为输入,并通过双重调度实现目标。
这是一种非常抽象的方式来表达我上面试图说的内容。通常你会将这些方法添加到元素中,但如果你不能,你必须将这些方法添加到其他东西中,并将其传递给进行处理。这是一些额外的工作,但如果情况合适,这可能是值得的。
如果您添加一个新的具体元素,那么您的所有访问者类都需要visit
为新元素添加一个新方法。如果您不使用访问者,则无论如何都必须将等效方法添加到新的具体元素中。
但是为每个访问者添加一个新方法可能比向一个新元素类添加等效的方法集更难。原因是访问者经常需要遍历元素树结构,并且可能需要在这样做时管理自己的状态数据。添加新visit
方法可能需要修改状态数据,这涉及考虑新方法如何与visit
其他元素的现有方法交互。
如果您没有访问者,将等效方法添加到您的新元素类可能会更简单,因为您只需要担心更具凝聚力的新具体元素的内部状态。
从本质上讲,访问者模式是一种数据操纵器,它将
一言以蔽之,访问者模式将扩展系统功能,而无需触及元素类定义。
但这是否意味着如果添加了新的具体元素类,则必须修改访问者类?我相信,这取决于访问者模式的设计和实现方式。
如果将visitor的所有访问方法拆分成visit functors,并动态绑定在一起,那么在扩展how系统时,无论是visitor还是visitee,都可能会更容易一些。
这是我几年前写的访问者模式的实现,代码有点旧,没有很好的修饰,但不知何故可以工作:)