C++设计模式
首先推荐一个C++设计模式的视频,我学习设计模式的时候就是看着这个视频学的,感谢up的分享。
另外,设计模式的代码来自于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++设计模式之策略模式的全部内容了。