当前位置: 首页 > article >正文

C++实现设计模式---访问者模式 (Visitor)

访问者模式 (Visitor)

访问者模式 是一种行为型设计模式,它允许你在不修改现有类的情况下向这些类添加新的行为。访问者模式将操作逻辑与对象结构分离,通过访问者对象实现新的行为。


意图

  • 通过将操作与数据结构分离,使得在不改变数据结构的前提下定义新的操作。
  • 使用访问者模式可以避免在对象中添加过多的方法。

使用场景

  1. 对象结构稳定,但需要增加新的操作
    • 数据结构相对稳定,但需要在上面定义多个操作。
  2. 需要跨多个类定义操作
    • 操作涉及多个类,但不希望将操作逻辑耦合到这些类中。
  3. 不希望污染类的接口
    • 通过访问者模式,避免在类中添加与操作无关的方法。

参与者角色

  1. 访问者接口 (Visitor)
    • 定义所有访问方法的接口,每种数据结构都需要对应的访问方法。
  2. 具体访问者 (ConcreteVisitor)
    • 实现访问者接口,定义具体的操作。
  3. 元素接口 (Element)
    • 定义接受访问者的方法,通常为 accept(Visitor&)
  4. 具体元素 (ConcreteElement)
    • 实现元素接口,调用访问者中的方法。
  5. 对象结构 (ObjectStructure)
    • 管理元素对象的集合,可以让访问者遍历这些元素。

示例代码

以下代码展示了访问者模式的实现,用于模拟不同类型员工的薪资计算(如全职员工和兼职员工)。

#include <iostream>
#include <vector>
#include <memory>

// 前置声明访问者接口
class FullTimeEmployee;
class PartTimeEmployee;

// 访问者接口
class Visitor {
public:
    virtual ~Visitor() = default;

    // 为不同元素定义访问方法
    virtual void visit(FullTimeEmployee& employee) = 0;
    virtual void visit(PartTimeEmployee& employee) = 0;
};

// 元素接口
class Employee {
public:
    virtual ~Employee() = default;

    // 接受访问者
    virtual void accept(Visitor& visitor) = 0;
};

// 具体元素:全职员工
class FullTimeEmployee : public Employee {
private:
    std::string name;
    double salary;

public:
    FullTimeEmployee(std::string name, double salary) 
        : name(std::move(name)), salary(salary) {}

    const std::string& getName() const { return name; }
    double getSalary() const { return salary; }

    void accept(Visitor& visitor) override {
        visitor.visit(*this); // 调用访问者的访问方法
    }
};

// 具体元素:兼职员工
class PartTimeEmployee : public Employee {
private:
    std::string name;
    double hourlyRate;

public:
    PartTimeEmployee(std::string name, double hourlyRate) 
        : name(std::move(name)), hourlyRate(hourlyRate) {}

    const std::string& getName() const { return name; }
    double getHourlyRate() const { return hourlyRate; }

    void accept(Visitor& visitor) override {
        visitor.visit(*this); // 调用访问者的访问方法
    }
};

// 具体访问者:薪资计算
class SalaryCalculator : public Visitor {
public:
    void visit(FullTimeEmployee& employee) override {
        std::cout << "计算全职员工 " << employee.getName() 
                  << " 的月薪:" << employee.getSalary() << " 元。
";
    }

    void visit(PartTimeEmployee& employee) override {
        std::cout << "计算兼职员工 " << employee.getName() 
                  << " 的时薪:" << employee.getHourlyRate() << " 元。
";
    }
};

// 对象结构:员工集合
class EmployeeList {
private:
    std::vector<std::shared_ptr<Employee>> employees;

public:
    void addEmployee(std::shared_ptr<Employee> employee) {
        employees.push_back(std::move(employee));
    }

    void accept(Visitor& visitor) {
        for (const auto& employee : employees) {
            employee->accept(visitor); // 让访问者操作每个员工
        }
    }
};

// 客户端代码
int main() {
    EmployeeList employeeList;

    // 添加员工
    employeeList.addEmployee(std::make_shared<FullTimeEmployee>("Alice", 8000));
    employeeList.addEmployee(std::make_shared<PartTimeEmployee>("Bob", 50));

    // 创建访问者
    SalaryCalculator calculator;

    // 计算薪资
    employeeList.accept(calculator);

    return 0;
}

代码解析

1. 访问者接口 (Visitor)
  • 定义了针对不同元素类型的访问方法。
  • 每种元素都需要对应一个访问方法。
class Visitor {
public:
    virtual ~Visitor() = default;
    virtual void visit(FullTimeEmployee& employee) = 0;
    virtual void visit(PartTimeEmployee& employee) = 0;
};
2. 元素接口 (Employee)
  • 定义了 accept 方法,接受访问者对象。
  • accept 方法会将自身传递给访问者。
class Employee {
public:
    virtual ~Employee() = default;
    virtual void accept(Visitor& visitor) = 0;
};
3. 具体元素类
  • FullTimeEmployeePartTimeEmployee 实现了元素接口。
  • 它们通过调用访问者的对应方法,实现了与访问者的交互。
class FullTimeEmployee : public Employee {
    void accept(Visitor& visitor) override {
        visitor.visit(*this);
    }
};
4. 具体访问者 (SalaryCalculator)
  • 实现了访问者接口。
  • 包含了对全职员工和兼职员工的具体操作逻辑。
class SalaryCalculator : public Visitor {
    void visit(FullTimeEmployee& employee) override {
        std::cout << "计算全职员工的薪资。
";
    }
    void visit(PartTimeEmployee& employee) override {
        std::cout << "计算兼职员工的薪资。
";
    }
};
5. 对象结构 (EmployeeList)
  • 用于管理多个元素,并提供 accept 方法将访问者应用到每个元素。
class EmployeeList {
    void accept(Visitor& visitor) {
        for (const auto& employee : employees) {
            employee->accept(visitor);
        }
    }
};

优缺点

优点
  1. 扩展性强
    • 可以在不修改元素类的情况下添加新的操作。
  2. 符合开闭原则
    • 通过增加新的访问者实现功能扩展。
  3. 集中管理逻辑
    • 访问者模式将相关操作集中在访问者类中,方便管理。
缺点
  1. 违反依赖倒置原则
    • 访问者模式依赖具体类,而非接口。
  2. 对象结构不稳定时扩展困难
    • 如果元素类经常变化,访问者需要频繁修改。
  3. 复杂性增加
    • 元素类需要对访问者暴露内部细节,可能增加复杂性。

适用场景

  1. 需要对对象结构中的对象执行多种操作
    • 如薪资计算、数据统计等。
  2. 对象结构稳定,但操作经常变化
    • 访问者模式可以方便地扩展新操作。
  3. 希望避免在类中添加不相关方法
    • 通过访问者模式,将操作逻辑从类中分离。

总结

访问者模式通过将操作逻辑封装到访问者中,实现了对象结构与操作逻辑的分离。它特别适用于对象结构稳定,而操作经常变化的场景。


http://www.kler.cn/a/499966.html

相关文章:

  • 解决 VSCode 调试时 Python 文件出现相对路径报错问题‘FileNotFoundError’
  • Swift 趣味开发:查找拼音首字母全部相同的 4 字成语(上)
  • 智慧充电桩可视化管理提升能源效率
  • xml简介
  • Docker中安装Tailscale方法一
  • OceanBase数据库设计与管理:构建高效分布式数据架构基石
  • Stable diffusion的SDXL模型,针不错!(含实操)
  • git push报错 unauthorized email account cannot submit code
  • 老榕树的java专题:探索 Nacos:微服务架构中的配置与服务发现利器
  • 【ArcGIS微课1000例】0138:ArcGIS栅格数据每个像元值转为Excel文本进行统计分析、做图表
  • C语言基本知识复习浓缩版:控制语句--循环
  • 汽车免拆诊断 | 2017 款东风风神 AX7 车热机后怠速不稳
  • 基于单片机的智能家居排气扇系统设计
  • 大语言模型分词器
  • MySQL库表的操作
  • 【2024年华为OD机试】 (A卷,100分)- 端口合并(Java JS PythonC/C++)
  • TCP__滑动窗口__拥塞控制
  • electron 环境配置,离线安装,npm无法安装
  • 美摄科技PC端视频编辑解决方案,为企业打造专属的高效创作平台
  • AI问答:vue项目props传递参数 / 传递一个对象都包含好 / 还是分开多个传递好