一、访问者设计模式概念
适用场景
- 如果你需要对一个复杂对象结构 (例如对象树) 中的所有元素执行某些操作, 可使用访问者模式。
- 可使用访问者模式来清理辅助行为的业务逻辑。
- 当某个行为仅在类层次结构中的一些类中有意义, 而在其他类中没有意义时, 可使用该模式。
访问者设计模式的结构:
- 访问者 (Visitor) 接口声明了一系列以对象结构的具体元素为参数的访问者方法。 如果编程语言支持重载, 这些方法的名称可以是相同的, 但是其参数一定是不同的。
- 具体访问者 (Concrete Visitor) 会为不同的具体元素类实现相同行为的几个不同版本。
- 元素 (Element) 接口声明了一个方法来 “接收” 访问者。 该方法必须有一个参数被声明为访问者接口类型。
- 具体元素 (Concrete Element) 必须实现接收方法。 该方法的目的是根据当前元素类将其调用重定向到相应访问者的方法。 请注意, 即使元素基类实现了该方法, 所有子类都必须对其进行重写并调用访问者对象中的合适方法。
- 客户端 (Client) 通常会作为集合或其他复杂对象 (例如一个组合 (opens new window)树) 的代表。 客户端通常不知晓所有的具体元素类, 因为它们会通过抽象接口与集合中的对象进行交互。
代码如下:
问题:做一款生成冰激凌和雪糕的程序,要求可以扩展新的口味,并且可以扩展新的包装方式。
解决方案:表示一个作用于某对象结构中的各元素的操作。
它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
#include <iostream>
#include <string>
#include <vector>
class IceCream;
class Popsicle;
class Visitor
{
public:virtual void visitIceCream(const IceCream *iceCream)const = 0;virtual void visitPopsicle(const Popsicle *popsicle)const = 0;
};class Component
{
public:virtual void accept(Visitor* visitor) const = 0;
};class IceCream : public Component
{
public:virtual void accept(Visitor* visitor) const{visitor->visitIceCream(this);}std::string getIceCream()const{return "冰激凌";}
};class Popsicle : public Component
{
public:virtual void accept(Visitor* visitor) const{visitor->visitPopsicle(this);}std::string getPopsicle()const{return "雪糕";}
};class Frosting : public Visitor
{
public:void visitIceCream(const IceCream* iceCream)const override{std::cout << iceCream->getIceCream() << " + 糖霜" << std::endl;}void visitPopsicle(const Popsicle* popsicle)const override{std::cout << popsicle->getPopsicle() << " + 糖霜" << std::endl;}
};class Chocolate : public Visitor
{
public:void visitIceCream(const IceCream* iceCream)const override{std::cout << iceCream->getIceCream() << " + 巧克力" << std::endl;}void visitPopsicle(const Popsicle* popsicle)const override{std::cout << popsicle->getPopsicle() << " + 巧克力" << std::endl;}
};void clientCode(const std::vector<Component*>& components,Visitor* visitor)
{for (const auto& component : components){component->accept(visitor);}
}int main()
{std::vector<Component*> components = { new IceCream,new Popsicle,new Popsicle };Frosting frosting;clientCode(components, &frosting);Chocolate chocolate;clientCode(components, &chocolate);return 0;
}
二、与其他模式的关系
- 你可以将访问者模式 (opens new window)视为命令模式 (opens new window)的加强版本, 其对象可对不同类的多种对象执行操作。
- 你可以使用访问者 (opens new window)对整个组合模式 (opens new window)树执行操作。
- 可以同时使用访问者 (opens new window)和迭代器模式 (opens new window)来遍历复杂数据结构, 并对其中的元素执行所需操作, 即使这些元素所属的类完全不同。