使用场景
访问者模式的目的是让我们在层次结构中每一个元素添加功能和行为。
侵入式访问者
从基类开始,添加入虚函数,随后在派生类中重载
违背了开闭原则、单一职责
反射式打印组件
通过dynamic函数对类型进行判断,进而根据类型进行操作
#include<vector>
#include<string>
#include<map>
#include<iostream>
#include <sstream>
using namespace std;
struct Expression {
virtual ~Expression() = default;
};
struct DoubleExpression :Expression {
double value;
explicit DoubleExpression(const double value) :value(value) {}
};
struct AdditionExpression :Expression {
Expression* left, * right;
AdditionExpression(Expression* const left, Expression* const right) :left(left), right(right) {}
~AdditionExpression(){ delete left; delete right; }
};
struct ExpressionPrinter {
void print(Expression* e) {
if (auto de = dynamic_cast<DoubleExpression*>(e)) {
oss << de->value;
}
else if (auto ae = dynamic_cast<AdditionExpression*>(e)) {
oss << "(";
oss << ae->left;
//print(ae->left, oss);
oss << "+";
oss << ae->right;
//print(ae->right, oss);
oss << ")";
}
}
string str()const { return oss.str(); }
private:
ostringstream oss;
};
int main()
{
auto e = new AdditionExpression{
new DoubleExpression{1} ,
new AdditionExpression{
new DoubleExpression{2},
new DoubleExpression{3}
}
};
ExpressionPrinter ep;
ep.print(e);
cout << ep.str() << endl;
return 0;
}
经典访问者
访问者的成员函数为visit()
整个层次中实现的成员函数通常称为accept()
#include<vector>
#include<string>
#include<map>
#include<iostream>
#include <sstream>
using namespace std;
struct DoubleExpression;
struct AdditionExpression;
struct ExpressionVisitor //各种访问者的基类
{
virtual void visit(DoubleExpression* de) = 0;
virtual void visit(AdditionExpression* ae) = 0;
};
struct ExpressionPrinter : ExpressionVisitor
{
ostringstream oss;
string str() const { return oss.str(); }
void visit(DoubleExpression* de); //override;
void visit(AdditionExpression* ae);// override;
};
struct Expression
{
virtual void accept(ExpressionVisitor* visitor) = 0; //虚函数中接收访问者
};
struct DoubleExpression :Expression {
double value;
DoubleExpression(const double value) :value(value) {}
void accept(ExpressionVisitor* visitor) { //所有派生类都要声明accept,用来接受访问者
visitor->visit(this);
}
};
struct AdditionExpression :Expression {
Expression* left, * right;
AdditionExpression(Expression* const left, Expression* const right) :left(left), right(right) {}
~AdditionExpression(){ delete left; delete right; }
void accept(ExpressionVisitor* visitor) { //所有派生类都要声明accept,用来接收访问者
visitor->visit(this);
}
};
void ExpressionPrinter::visit(DoubleExpression* ae) //双重分发,根据指针类型实现多态
{
oss << ae->value;
}
void ExpressionPrinter::visit(AdditionExpression* ae)
{
oss << "(";
ae->left->accept(this);
oss << "+";
ae->right->accept(this);
oss << ")";
}
int main()
{
auto e = new AdditionExpression{
new DoubleExpression{1} ,
new AdditionExpression{
new DoubleExpression{2},
new DoubleExpression{3}
}
};
ostringstream oss;
ExpressionPrinter ep;
ep.visit(e); //仍然利用双重分发
cout << ep.str() << endl; //(1+(2+3))
}
总结
侵入式方法:通过为结构中每个对象添加虚函数,但是违反了开闭原则,单一功能原则
反射方式:通过定义单独的访问者,使用dynamic_cast实现分发
经典分发:双重分发,用通用的方式对结构修改,每个元素都会通过accept()接受访问者,进而对访问者细分,实现分发