【设计模式】之二十三种设计模式--访问者模式

访问者模式

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
(封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。)

通用类图

抽象访问者类
抽象类,声明访问者可以访问哪些元素
具体访问者类
继承其抽象,影响访问者访问到一个类后要做什么事情
抽象元素类
抽象类,声明接受哪一类访问者访问
具体元素类
继承其抽象,实现抽象元素类中的方法
结构对象类
元素产生者,一般容纳在多个不同类、不同接口的容器。

通用源码

//抽象元素类
class Element {
public:
    virtual void doSomething() = 0;
    virtual void accept(IVisitor*) = 0;
};
//具体元素类
class ConcreteElement1 : public Element {
public:
    //实现业务逻辑
    void doSomething override {
    }
    //允许哪个访问者访问
    void accept(IVisitor* visitor) override {
        visitor->visit(this);
    }
};
class ConcreteElement2 : public Element {
public:
    void doSomething override {
    }
    void accept(IVisitor* visitor) override {
        visitor->visit(this);
    }
};
//抽象访问者类
class IVisitor {
public:
    virtual void visit(ConcreteElement1*) = 0;
    virtual void visit(ConcreteElement2*) = 0;
};
//具体访问者类
class Visitor : public IVisitor {
public:
    void visit(ConcreteElement1* ce) override {
        ce->doSomething();
    }
    void visit(ConcreteElement2* ce) override {
        ce->doSomething();
    }
};
//结构对象类
class ObjectStructure {
    //生成ConcreteElement1和ConcreteElement2对象
};

优点

符合单一职责原则
优秀的扩展性
灵活性非常高

缺点

具体元素对访问者公布细节,违背了迪米特法则
具体元素变更比较困难,具体元素变更会引起访问者类改变
违背了依赖倒置原则

使用场景

一个对象结构包含多类对象
需要对一个对象结构中的对象进行很多不同且不相关的操作
业务规则要求遍历多个不同的对象

扩展

统计功能
多个访问者
双分派

示例代码

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

using namespace std;

class IVisitor;
class Employee {
public:
    Employee(string n, int s, int e): name(n), salary(s), sex(e) { }
    void setName(string n) {
        name = n;
    }
    string getName() {
        return name;
    }
    void setSalary(int n) {
        salary = n;
    }
    int getSalary() {
        return salary;
    }
    void setSex(int n) {
        sex = n;
    }
    int getSex() {
        return sex;
    }
    virtual void accept(IVisitor*) = 0;
private:
    string name;
    int salary;
    int sex; //0:male, 1:famale
};

class CommonEmployee : public Employee {
public:
    CommonEmployee(string n, int s, int e, string j):Employee(n,s,e), job(j) { }
    string getJob() { return job;}
    void setJob(string s) { job = s;}
    void accept(IVisitor*);
private:
    string job;
};

class Manager : public Employee {
public:
    Manager(string n, int s, int e, string p):Employee(n,s,e), performance(p) { }
    string getPerformance() { return performance;}
    void setPerformance(string s) { performance = s;}
    void accept(IVisitor*);
private:
    string performance;
};

class IVisitor {
public:
    virtual void visit(CommonEmployee*) = 0;
    virtual void visit(Manager*) = 0;
};

class Visitor : public IVisitor {
public:
    void visit(CommonEmployee* commonEmployee) {
        cout << getCommonEmployeeInfo(commonEmployee) << endl;
    }
    void visit(Manager* manager) {
        cout << getManagerInfo(manager) << endl;
    }
private:
    string getBasicInfo(Employee* employee) {
        string info = "name: " + employee->getName() + "\t";
        info += "sex: " + to_string(employee->getSex());
        info += "\tsalary: " + to_string(employee->getSalary());
        return info;
    }
    string getManagerInfo(Manager* manager) {
        string mInfo = getBasicInfo(manager);
        mInfo += "\twork: " + manager->getPerformance() + "\t";
        return mInfo;
    }
    string getCommonEmployeeInfo(CommonEmployee* commonEmployee) {
        string cInfo = getBasicInfo(commonEmployee);
        cInfo += "\tjob: " + commonEmployee->getJob() + "\t";
        return cInfo;
    }
};

void CommonEmployee::accept(IVisitor* visitor) { visitor->visit(this); }
void Manager::accept(IVisitor* visitor) { visitor->visit(this); }

int main() {
    vector<Employee*> ve;
    CommonEmployee* zhang = new CommonEmployee("zhang", 1800, 0, "coding java");
    CommonEmployee* Li = new CommonEmployee("Li", 1900, 1, "Ui Design");
    Manager* Wang = new Manager("Wang", 18750, 0, "pai ma pi max");
    ve.push_back(zhang);
    ve.push_back(Li);
    ve.push_back(Wang);
    Visitor v;
    for(auto e : ve) {
        e->accept(&v);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值