C++设计模式(总结)

解释器模式

什么是解释器模式

解释器模式是属于行为型模式,它提供了评估语言的语法或表达式的方式,这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。

为什么使用解释器模式

在软件开发中,会遇到有些问题多次重复出现,而且有一定的相似性和规律性。如果将它们归纳成一种简单的语言,那么这些问题实例将是该语言的一些句子,这样就可以用“编译原理”中的解释器模式来实现了。虽然使用解释器模式的实例不是很多,但对于满足以上特点,且对运行效率要求不是很高的应用实例,如果用解释器模式来实现,其效果是非常好的

解释器模式实现步骤

1.提供一个解释器上下文环境类:用来存储解释器的上下文环境,比如需要解释的文法,一般用来传递被所有解释器共享的数据

2.提供一个解释器抽象类:定义解释器的接口,约定解释器的解释操作

3.提供一个终结符解释器的具体实现类:用来实现语法规则中和终结符相关的操作

4.提供一个非终结符解释器:用来实现语法规则中非终结符相关的操作,通常一个解释器对应一个语法规则,可以包含其他解释器

// a+b-c 表达式求值运算
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <typeinfo>
using namespace std;
//抽象表达式
class Expression {
   public:
    virtual int Interpreter(map<string, int>& var) = 0;
};
//变量解析器
class VarExpression : public Expression {
   public:
    VarExpression(string key) { this->key = key; }
    int Interpreter(map<string, int>& var) { return var[key]; }

   private:
    string key;
};
//运算符解析器
class SymbolExpression : public Expression {
   protected:
    Expression* left;
    Expression* right;

   public:
    SymbolExpression(Expression* left, Expression* right)
        : left(left), right(right) {}
    Expression* GetLeft() { return left; }
    Expression* GetRight() { return right; }
};
//加法解析器
class AddExpresion : public SymbolExpression {
   public:
    AddExpresion(Expression* left, Expression* right)
        : SymbolExpression(left, right) {}
    int Interpreter(map<string, int>& var) {
        return left->Interpreter(var) + right->Interpreter(var);
    }
};
//减法解析器
class SubExpresion : public SymbolExpression {
   public:
    SubExpresion(Expression* left, Expression* right)
        : SymbolExpression(left, right) {}
    int Interpreter(map<string, int>& var) {
        return left->Interpreter(var) - right->Interpreter(var);
    }
};
//解析器封装类   封装调用接口
class Calculator {
   private:
    Expression* expression;

   public:
    //解析表达式,构建语法树  a+b-c
    Calculator(string expStr) {
        expression = NULL;
        stack<Expression*> stkExp;
        Expression* left = NULL;
        Expression* right = NULL;
        for (int i = 0; i < expStr.length(); i++) {
            switch (expStr[i]) {
                case '+':
                    //先从栈中取出左操作数
                    left = stkExp.top();
                    stkExp.pop();

                    //从表达式中取出+号后面的右操作数,并生成终结符解析对象
                    right = new VarExpression(expStr.substr(++i, 1));

                    //将左右操作数相加,并把结果放入栈中
                    stkExp.push(new AddExpresion(left, right));
                    break;
                case '-':
                    //先从栈中取出左操作数
                    left = stkExp.top();
                    stkExp.pop();

                    //从表达式中取出+号后面的右操作数,并生成终结符解析对象
                    right = new VarExpression(expStr.substr(++i, 1));

                    //将左右操作数相加,并把结果放入栈中
                    stkExp.push(new SubExpresion(left, right));

                    break;
                default:
                    stkExp.push(new VarExpression(expStr.substr(i, 1)));
            }
        }
        //栈中保存的就是最终语法树的根结点
        //本例为SubExpression对象
        if (!stkExp.empty()) {
            expression = stkExp.top();
            stkExp.pop();
        }
    }
    int Run(map<string, int>& var) {
        return (expression == NULL) ? 0 : expression->Interpreter(var);
    }
};

int main() {
    string expstr = "a+b-c";
    map<string, int> var;
    var["a"] = 300;
    var["b"] = 20;
    var["c"] = 30;
    Calculator cal(expstr);
    cout << cal.Run(var) << endl;
    return 0;
}

解释器模式优缺点

优点

  • 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。

  • 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易

缺点

  • 执行效率较低。解释器模式中通常使用大量的循环和递归调用,句子较复杂时,运行速度很慢,且代码的调试过程也比较麻烦

  • 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护

迭代器模式

什么是迭代器模式

迭代器模式是一种行为设计模式, 让你能在不暴露集合底层表现形式 (C++STL中的迭代器) 的情况下遍历集合中所有的元素

为什么使用迭代器模式

迭代器封装了与复杂数据结构进行交互的细节, 为客户端提供多个访问集合元素的简单方法。 这种方式不仅对客户端来说非常方便, 而且能避免客户端在直接与集合交互时执行错误或有害的操作, 从而起到保护集合的作用。

重要迭代算法的代码往往体积非常庞大。 当这些代码被放置在程序业务逻辑中时, 它会让原始代码的职责模糊不清, 降低其可维护性。 因此, 将遍历代码移到特定的迭代器中可使程序代码更加精炼和简洁。

迭代器模式实现步骤

1.提供一个迭代器类抽象类:抽象实现迭代功能的最小定义方法集

2.提供一个迭代器类:定义实现迭代功能的最小定义方法集

3.提供一个容器抽象类:抽象基本功能以及提供类似迭代器类的方法

4.提供一个容器具体类:定义基本功能以及提供类似迭代器类的方法

//迭代器模式
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template <typename T, typename U>
class Iterator {
   public:
    typedef typename vector<T>::iterator iter_type;
    Iterator(U* data, bool reverse = false) : m_data(data) {
        iter = data->m_data.begin();
    }
    void Begin() { iter = m_data->m_data.begin(); }
    void Next() { iter++; }
    bool End() { return (iter == m_data->m_data.end()); }
    iter_type Current() { return iter; }

   private:
    U* m_data;
    iter_type iter;
};

template <class T>
class Container {
    friend class Iterator<T, Container>;

   public:
    void Add(T data) { m_data.push_back(data); }
    Iterator<T, Container>* CreateIterator() {
        return new Iterator<T, Container>(this);
    }

   protected:
    vector<T> m_data;
};

class Data {
   public:
    Data(int data = 0) : m_data(data) {}
    void SetData(int data) { m_data = data; }
    int data() { return m_data; }

   private:
    int m_data;
};
int main() {
    Container<int> test;
    for (int i = 0; i < 10; i++) {
        test.Add(i);
    }
    Iterator<int, Container<int>>* iter = test.CreateIterator();
    for (iter->Begin(); !iter->End(); iter->Next()) {
        cout << *iter->Current() << " ";
    }
    cout << endl;
    Container<Data> test2;
    test2.Add(Data(100));
    test2.Add(Data(200));
    test2.Add(Data(300));
    Iterator<Data, Container<Data>>* iter2 = test2.CreateIterator();
    for (iter2->Begin(); !iter2->End(); iter2->Next()) {
        cout << iter2->Current()->data() << " ";
    }
    return 0;
}

迭代器模式优缺点

优点

  • 单一职责原则: 通过将体积庞大的遍历算法代码抽取为独立的类, 你可对客户端代码和集合进行整理

  • 开闭原则: 你可实现新型的集合和迭代器并将其传递给现有代码, 无需修改现有代码

  • 你可以并行遍历同一集合, 因为每个迭代器对象都包含其自身的遍历状态

缺点

  • 如果你的程序只与简单的集合进行交互, 应用该模式可能会矫枉过正

  • 对于某些特殊集合, 使用迭代器可能比直接遍历的效率低

设计模式总结

创建型模式总结

  • 工厂模式模式:单个类的对象创建工作

  • 抽象工厂模式:多个类的对象创建工作

  • 单例模式:类的全局对象创建工作

  • 建造者模式:复杂类的对象创建工作

  • 原型模式:自身类的克隆工作

结构体型模式总结

  • 代理模式:提供第三方进行控制访问对象

  • 装饰者模式:为对象添加新功能

  • 适配器模式:不兼容的类进行融合过程

  • 桥接模式:分离变化部分成为独立的一部分

  • 组合模式:整体和局部进行递归组合

  • 外观模式: 表面工程(对外提供统一接口访问子系统)

  • 享元模式:使用对象池减少重复对象的创建

行为型模式总结

  • 模板方法模式:通过定义一套流程模板进行流程化处理

  • 命令模式:请求成为命令,记录下

  • 责任链模式:踢皮球(对象连接成为链,通过链进行传递请求)

  • 策略模式:封装不同算法,算法之间可以互相转换

  • 中介者模式:租房中介(中介者类做转发操作)

  • 观察者模式:交通警察指挥路口(状态发生改变通知观察者)

  • 备忘录模式:保存对象状态,可以进行回复

  • 访问者模式:稳定的数据结构,定义新的操作行为

  • 状态模式:根据不同的状态做不同的行为

  • 解释器模式:给定规则,定义语法,定义解释器,做句子分析(摩斯密码解析过程)

  • 迭代器模式:提供一个中方法顺序的访问复合对象的各个元素

关于设计模式的建议

  • 不存在完美的设计模式,只存在最适合的设计模式

  • 原有的设计模式并不重要,设计原则才是最重要

  • 有意无意注意模式问题,通过原则写出自己的设计方法才是最重要的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值