访问者模式
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);
}
}