访问者模式 -- 操作对象,分离算法
访问者模式(Visitor Pattern)是一种将算法与对象结构分离的设计模式。这种模式主要用于操作一个由许多对象构成的复杂对象结构,它能够在不修改这些对象的类的前提下定义作用于这些对象的新操作。
组成
- 访问者(Visitor)接口:定义了对每一个元素(Element)类访问操作的接口。通常会有一个访问方法对应每种类型的元素。
- 具体访问者(Concrete Visitor)类:实现访问者接口,定义了对每一个元素的具体访问行为。
- 元素(Element)接口:定义了一个接受访问者的方法(accept),该方法通常有一个访问者作为参数。
- 具体元素(Concrete Element)类:实现元素接口,定义了接受访问者的具体操作,通常是让访问者访问自己的元素。
- 对象结构(Object Structure):一个元素的集合,它提供了一个接口,允许访问者遍历自己的元素。
工作原理
- 访问者模式通过将数据结构与数据操作分离,使得在不修改已有程序结构的情况下,可以向已有的对象结构中添加新的操作。
- 当需要对一个复杂的对象结构(如组合树)进行操作时,可以使用访问者模式来避免对每个节点类都添加操作。相反,可以创建访问者类来专门处理这些操作。
- 元素类通过接受一个访问者对象,将自身作为参数传递给访问者的访问方法,从而实现对元素的操作。
优点
- 易于添加新的操作,增强了系统的灵活性。
- 将相关的操作集中到一个访问者对象中,而不是分散在多个元素类中,有助于集中管理和维护。
缺点
- 增加新的元素类变得困难,因为每增加一个新的元素类,都需要在每个访问者类中增加相应的访问操作。
- 可能会破坏封装,因为访问者模式通常需要元素类暴露一些访问其内部状态的操作,这可能会违反其封装原则。
实现
- 访问者(Visitor)接口:定义了对每一个元素(Element)类访问操作的接口。通常会有一个访问方法对应每种类型的元素。
cpp
class Visitor {
public:
virtual void visitConcreteElementA(ConcreteElementA* elementA) = 0;
virtual void visitConcreteElementB(ConcreteElementB* elementB) = 0;
virtual ~Visitor() = default;
};
- 具体访问者(Concrete Visitor)类:实现访问者接口,定义了对每一个元素的具体访问行为。
cpp
// 具体访问者1
class ConcreteVisitor1 : public Visitor {
public:
void visitConcreteElementA(ConcreteElementA* elementA) override {
std::cout << "ConcreteVisitor1 visiting ConcreteElementA" << std::endl;
elementA->operationA();
}
void visitConcreteElementB(ConcreteElementB* elementB) override {
std::cout << "ConcreteVisitor1 visiting ConcreteElementB" << std::endl;
elementB->operationB();
}
};
// 具体访问者2
class ConcreteVisitor2 : public Visitor {
public:
void visitConcreteElementA(ConcreteElementA* elementA) override {
std::cout << "ConcreteVisitor2 visiting ConcreteElementA" << std::endl;
elementA->operationA();
}
void visitConcreteElementB(ConcreteElementB* elementB) override {
std::cout << "ConcreteVisitor2 visiting ConcreteElementB" << std::endl;
elementB->operationB();
}
};
- 元素(Element)接口:定义了一个接受访问者的方法(accept),该方法通常有一个访问者作为参数。
cpp
class Element {
public:
virtual void accept(Visitor* visitor) = 0; // 接受访问者
virtual ~Element() = default;
};
- 具体元素(Concrete Element)类:实现元素接口,定义了接受访问者的具体操作,通常是让访问者访问自己的元素。
cpp
// 具体元素A
class ConcreteElementA : public Element {
public:
void accept(Visitor* visitor) override {
visitor->visitConcreteElementA(this);
}
void operationA() {
std::cout << "ConcreteElementA operationA" << std::endl;
}
};
// 具体元素B
class ConcreteElementB : public Element {
public:
void accept(Visitor* visitor) override {
visitor->visitConcreteElementB(this);
}
void operationB() {
std::cout << "ConcreteElementB operationB" << std::endl;
}
};
- 对象结构(Object Structure):一个元素的集合,它提供了一个接口,允许访问者遍历自己的元素。
cpp
int main() {
std::vector<std::unique_ptr<Element>> elements;
elements.push_back(std::make_unique<ConcreteElementA>());
elements.push_back(std::make_unique<ConcreteElementB>());
ConcreteVisitor1 visitor1;
ConcreteVisitor2 visitor2;
for (auto& element : elements) {
element->accept(&visitor1);
element->accept(&visitor2);
}
return 0;
}
- 结果
shell
ConcreteVisitor1 visiting ConcreteElementA
ConcreteElementA operationA
ConcreteVisitor2 visiting ConcreteElementA
ConcreteElementA operationA
ConcreteVisitor1 visiting ConcreteElementB
ConcreteElementB operationB
ConcreteVisitor2 visiting ConcreteElementB
ConcreteElementB operationB