行为型模式-访问者模式

发布时间 2023-11-14 22:07:17作者: Qt小罗

1 什么是访问者模式

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许在不改变数据结构的前提下定义作用于数据结构元素的新操作。使用访问者模式,可以将数据结构和数据操作相分离,从而使得数据结构的修改和数据操作的增加变得更加容易。

在访问者模式中,包括以下几个核心角色:

  • Visitor(访问者):定义了对数据结构中各个元素进行访问的操作接口,每个操作对应一个具体的访问者实现。
  • ConcreteVisitor(具体访问者):实现了Visitor接口中定义的各个操作,负责对数据结构中各个元素的具体访问操作。
  • Element(元素):定义了一个 accept 方法,该方法接收一个访问者作为参数,根据访问者的不同调用对应的 visit 方法。
  • ConcreteElement(具体元素):实现了Element接口,具体的数据元素类,包含了 accept 方法的具体实现。
  • ObjectStructure(对象结构):表示数据结构,负责容纳元素对象,并提供接口让访问者对象访问元素。

2 举个例子

下面以一个简单的员工数据结构和访问者模式为例来说明。

#include <iostream>
#include <vector>
#include <string>

// 前向声明员工类
class Employee;

// 访问者接口
class Visitor {
public:
    virtual void visit(Employee& employee) = 0;
    virtual ~Visitor() {}
};

// 具体访问者类:人力资源部访问者
class HRVisitor : public Visitor {
public:
    virtual void visit(Employee& employee) override {
        std::cout << "人力资源部正在处理员工:" << employee.getName() << std::endl;
    }
};

// 具体访问者类:财务部访问者
class FinanceVisitor : public Visitor {
public:
    virtual void visit(Employee& employee) override {
        std::cout << "财务部正在处理员工:" << employee.getName() << std::endl;
    }
};

// 元素接口
class Element {
public:
    virtual void accept(Visitor& visitor) = 0;
    virtual ~Element() {}
};

// 具体元素类:员工类
class Employee : public Element {
private:
    std::string name;

public:
    Employee(const std::string& name) : name(name) {}

    std::string getName() const {
        return name;
    }

    virtual void accept(Visitor& visitor) override {
        visitor.visit(*this);
    }
};

// 对象结构类:员工列表
class Employees {
private:
    std::vector<Employee> employees;

public:
    void attach(const Employee& employee) {
        employees.push_back(employee);
    }

    void detach(int index) {
        employees.erase(employees.begin() + index);
    }

    void accept(Visitor& visitor) {
        for (Employee& employee : employees) {
            employee.accept(visitor);
        }
    }
};

// 客户端代码
int main() {
    Employees employees;
    employees.attach(Employee("张三"));
    employees.attach(Employee("李四"));

    HRVisitor hrVisitor;
    FinanceVisitor financeVisitor;

    std::cout << "人力资源部正在处理员工:" << std::endl;
    employees.accept(hrVisitor);

    std::cout << "财务部正在处理员工:" << std::endl;
    employees.accept(financeVisitor);

    return 0;
}

在上面的示例中,我们首先定义了Visitor接口和两个具体访问者类HRVisitor和FinanceVisitor,它们分别用于处理员工信息。然后我们定义了Employee类作为具体元素类,实现了Element接口的accept方法用以接受访问者的访问。Employees类作为对象结构类,用来存储员工信息并提供统一的接口给访问者访问。

在客户端代码中,我们创建了两个具体访问者hrVisitor和financeVisitor,然后通过employees的accept方法分别将它们应用到员工列表中的每一个员工上,从而实现了不同部门对员工的处理操作。

3 总结

通过访问者模式,我们可以轻松地扩展对数据结构的操作,而无需改变现有的数据结构和数据元素类,使得算法的实现和数据结构的变化可以相互独立,并且易于扩展。