2021-09-10

C++设计模式

首先推荐一个C++设计模式的视频,我学习设计模式的时候就是看着这个视频学的,感谢up的分享。

c++设计模式

另外,设计模式的代码来自于github上的开源代码,记得给大佬点个star,这里贴出地址:

设计模式开源代码

策略模式

首先考虑我们如果有一个任务,就是根据各国的税法来计算不同地区需要缴纳的税款。按照之前的思路,我们可能会这样做。

//
// Created by devil on 2021/9/10.
//
#include <iostream>

enum Condition{
    ConditionA,ConditionB,ConditionC
};
void condition_algorithm(Condition _condition);
int main(){
    Condition condition=ConditionA;
    condition_algorithm(condition);
    return 0;
}
void condition_algorithm(Condition _condition){
    if(_condition==ConditionA){
        //....
        std::cout<<"Handle ConditionA!"<<std::endl;
    }else if(_condition==ConditionB){
        //...
        std::cout<<"Handle ConditionB!"<<std::endl;

    }else{
        //...
        std::cout<<"Handle ConditionC!"<<std::endl;
    }
}

当你以不变的眼光看待问题的时候,这种方法当然是可行的。但是,很多的情况下,正是因为需求的不断变化,引起了代码的变化,然后代码改变倒成了工作量变大,bug变多。设计模式需要解决的便是这个问题,我们希望找到通用的解决方法来解决某一类代码结构上的问题。

按照我们之前所说的,这个时候用户提了需求说我们还需要添加另外一种情况,这个时候你可能会说了,直接在代码上再添加一种情况就好了吗,是的你说的对,但是当代码变多,需要改动的地方变多的时候你可能就会烦躁生气了。

这其实是违反了面向对象设计原则的开放封闭原则,正确的设计应该是对扩展开放的,对更改封闭的。也就是我们应该尽力做到能够使代码进行扩展而适应新的变化,而不是修改原来的代码来适应变化。

还有需要纠正的一点就是,在原来的代码上添加新的代码并不是对老代码的重用,真正意义上的重用是指编译单元上的重用。你扩展类的时候,原来的类依旧可以使用。这才是重用的意义。c++的对象模型也在尽力的支持这一方法。

好了,我们现在来看一下使用策略模式下的代码应该如何书写:

/*
 * C++ Design Patterns: Strategy
 * Author: Jakub Vojvoda [github.com/JakubVojvoda]
 * 2016
 *
 * Source code is licensed under MIT License
 * (for more details see LICENSE)
 *
 */

#include <iostream>

/*
 * Strategy
 * declares an interface common to all supported algorithms
 */
class Strategy
{
public:
  virtual ~Strategy() { /* ... */ }
  virtual void algorithmInterface() = 0;
  // ...
};

/*
 * Concrete Strategies
 * implement the algorithm using the Strategy interface
 */
class ConcreteStrategyA : public Strategy
{
public:
  ~ConcreteStrategyA() { /* ... */ }
  
  void algorithmInterface()
  {
    std::cout << "Concrete Strategy A" << std::endl;
  }
  // ...
};

class ConcreteStrategyB : public Strategy
{
public:
  ~ConcreteStrategyB() { /* ... */ }
  
  void algorithmInterface()
  {
    std::cout << "Concrete Strategy B" << std::endl;
  }
  // ...
};

class ConcreteStrategyC : public Strategy
{
public:
  ~ConcreteStrategyC() { /* ... */ }
  
  void algorithmInterface()
  {
    std::cout << "Concrete Strategy C" << std::endl;
  }
  // ...
};

/*
 * Context
 * maintains a reference to a Strategy object
 */
class Context
{
public:
  Context( Strategy* const s ) : strategy( s ) {}
  
  ~Context()
  {
    delete strategy;
  }
  
  void contextInterface()
  {
    strategy->algorithmInterface();
  }
  // ...

private:
  Strategy *strategy;
  // ...
};


int main()
{
  Context context( new ConcreteStrategyA() );
  context.contextInterface();
  
  return 0;
}

看完上面的代码就知道,Strategy对外提供的接口都是一致的,然后通过多态的方式能够实现使用不同的策略。

不管是实际的策略也好,还是上层的代码也好都依赖于一个稳定的接口,这个稳定的接口我们一旦定义好就不会再做更改了,这也是面向对象设计原则中的依赖倒置原则。

高层模块不应该依赖于底层模块,二者都应该依赖于抽象
抽象不应该依赖于实现细节,实现细节应该依赖于抽象

好,这就是c++设计模式之策略模式的全部内容了。

上一篇:设计模式之策略模式


下一篇:MyBatisPlus代码生成器