访问者模式——现代C++设计模式

使用场景

访问者模式的目的是让我们在层次结构中每一个元素添加功能和行为。

侵入式访问者

从基类开始,添加入虚函数,随后在派生类中重载
违背了开闭原则、单一职责

反射式打印组件

通过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()接受访问者,进而对访问者细分,实现分发

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值