定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)
策略 ——普通语境下,是我们对一件事情的处理方法,由于对不同的事情我们有不同的应对方式,我们通过权衡利弊,得到合适的方案,这个过程就是挑选策略。
在面向对象编程中,对于某类事务,有着不同的处理方式,将这些方式向上抽象一层就有了策略模式。这里并不是说一般的处理方式不能完成任务,而是我们的代码是面对变化的需求的,我们要让代码简单方便维护,所以才需要此类设计模式。
比如,对于早餐来说,想吃馒头、包子、吃油条、吃面包…就要自己买或者自己做这些食物,我们把得到某食物的过程称为做(make)某食物(无论是自己做还是买),早餐吃什么完全取决于自己的想法,想吃啥就要有人做它,现在需求是根据自己的想法显示主食的制作过程,有伪代码如下:
enum StapleFood{ // 主食
ManTou, // 馒头
BaoZi, // 包子
YouTiao, // 油条
MianBao, // 面包
};
class Breakfast {// 早餐类
private:
StapleFood staplefood;
public:
Breakfast() {}
Breakfast(StapleFood stfood) : staplefood(stfood) {}
void setStapleFood(StapleFood stfood) {
staplefood = stfood;
}
void MakeFoodInfo() {
if (staplefood == Mantou) {
cout << "正在蒸馒头" << endl;
cout << "......" << endl; // 蒸馒头一系列复杂操作
} else if (staplefood == Baozi ) {
cout << "正在做包子:" << endl;
cout << "......" << endl; // 做包子一系列操作
} else if (staplefood == YouTiao) {
cout << "正在炸油条:" << endl;
cout << "......" << endl; // 炸油条一系列操作
}
}
};
当主食随着时代发展,可能出现几十上百种食物,它们制作过程各不相同,而且工艺复杂,想要增加一种早餐主食,至少要修改:
enum StapleFood{ // 主食
ManTou, // 馒头
BaoZi, // 包子
YouTiao, // 油条
MianBao, // 面包
添加主食类型
};
void MakeFoodInfo() {
if (staplefood == Mantou) {
cout << "正在蒸馒头" << endl;
cout << "......" << endl; // 蒸馒头一系列复杂操作
} else if (staplefood == Baozi ) {
cout << "正在做包子:" << endl;
cout << "......" << endl; // 做包子一系列操作
} else if (staplefood == YouTiao) {
cout << "正在炸油条:" << endl;
cout << "......" << endl; // 炸油条一系列操作
} else if(staplefood == 添加的主食) {
添加制作该食物的过程
}
}
严重违反开闭原则! ,因为一旦添加一种食物,就要在原先的结构上修修改改,这样很容易出错,策略模式应运而生。
策略模式的做法很简单,也就是我在上面所说的,将这些方式向上抽象一层,利用多态的特性,在C++中让子类继承抽象基类,在java中还可以通过实现抽象接口的形式操作(后面会讲到)。
沿承上面的早餐的例子,对于主食我们完全可以做一个抽象,如下:
class StapleFood {
public:
StapleFood() {}
virtual void MakeFoodInfo() = 0;
virtual ~StapleFood() {}
};
此时,主食是一个抽象类,因为其含有纯虚函数。
对于目前的主食信息,有:
class MaTou : public StapleFood
{
virtual void MakeFoodInfo() {
cout << "正在蒸馒头" << endl;
cout << "......" << endl; // 蒸馒头一系列复杂操作
}
};
class BaoZi : public StapleFood
{
virtual void MakeFoodInfo() {
cout << "正在做包子:" << endl;
cout << "......" << endl; // 做包子一系列操作
}
};
class YouTiao : public StapleFood
{
virtual void MakeFoodInfo() {
cout << "正在炸油条:" << endl;
cout << "......" << endl; // 炸油条一系列操作
}
};
这时候把所有美食的制作都交给厨师统一管理:
class Cook {
private:
StapleFood* staplefood;
public:
Cook() {}
Cook(StapleFood* stfood) : staplefood(stfood) {}
void setStapleFood(StapleFood* stfood) {
staplefood = stfood;
}
void MakeFoodInfo() {
if (staplefood == nullptr) {
cout << "厨师没有做饭——饿着吧(谁让你没告诉厨师想吃什么)" << endl;
return;
}
staplefood->MakeFoodInfo();
}
}
如果早餐想吃包子,就这样告诉厨师:
int main() {
Cook* cook = new Cook();// new (找)一个厨师
cook->setStapleFood(new BaoZi()); // 告诉厨师想吃包子
cook->MakeFoodInfo(); // 厨师开始做包子
return 0;
}
也可以, new出厨师的同时指定厨师做某种食物(现实意义就是为了吃某种食物专门聘请厨师)
int main() {
BaoZi* baozi = new BaoZi(); // 想吃包子了
Cook *cook = new Cook(baozi);// 找一个超级会做包子的厨师
cook->MakeFoodInfo(); // 厨师开始做包子
return 0;
}
这个时候当主食随着时代发展,比如推出了新的主食——奥力给,拓展只要新建文件:
class AoLiGei : public StapleFood
{
virtual void MakeFoodInfo() {
cout << "正在制作奥里给:" << endl;
cout << "......" << endl; // make奥里给一系列操作
}
};
这样,并没有修改旧的文件,这里说明一下,一般开发,一个类是放在一个.cpp和.h文件里面的,.h为类的声明,.cpp里面是对类的方法的实现(不考虑内联类,上面代码均为内联而且一个文件里面出现多个类,只是为了方便),我们这种做法(指策略模式),并没有改变旧文件,而是添加了新文件,根本不会对以前的业务造成影响,拓展性极强!
这个时候走进来一个美食家: ——嗨害嗨!虽然不是同一个时间,但是在同一个撤硕
针对它的口味,我们可以新建一个AoLiGei类继承自StapleFood(主食),其他地方不需要大的改动。
int main() {
AoLiGei* aoligei = new AoLiGei(); // 想吃***了
Cook *cook = new Cook(aoligei);// 不用厨子了,自产自销————指自己做自己吃(杆菌又卫生)
cook->MakeFoodInfo(); // making 造它就完了!干了~奥里给!
return 0;
}
代码被我调试过,和老师讲课的时候略有不同,老师上课用的伪代码
初始代码:
// test02.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
enum TaxBase{
CN_Tax,
US_Tax,
DE_Tax,
FR_Tax
};
class SalesOrder {
TaxBase tax;
public:
void setTaxType(TaxBase tax) {
this->tax = tax;
}
double CalculateTax() {
double val = 0.0;
//...
if (tax == CN_Tax) {
return 1.0;
} else if (tax == US_Tax) {
return 2.0;
} else if (tax == DE_Tax) {
return 3.0;
} else if (tax == FR_Tax) {
return 4.0;
}
//...
return val;
}
};
int main() {
SalesOrder* salesOrder = new SalesOrder();
salesOrder->setTaxType(US_Tax);
cout << salesOrder->CalculateTax() << endl;
return 0;
}
改进代码:
// test01.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
class Context {
public:
Context() {}
};
class TaxStrategy {
public:
virtual double Calculate(const Context& context) = 0;
virtual ~TaxStrategy() {}
};
class CNTax : public TaxStrategy {
public:
virtual double Calculate(const Context& context) {
double res = 0.0;
//***********
return res;
}
};
class USTax : public TaxStrategy {
public:
virtual double Calculate(const Context& context) {
double res = 1.0;
//***********
return res;
}
};
class DETax : public TaxStrategy {
public:
virtual double Calculate(const Context& context) {
double res = 2.0;
//***********
return res;
}
};
//扩展
//*********************************
class FRTax : public TaxStrategy {
public:
virtual double Calculate(const Context& context) {
double res = 3.0;
//.........
return res;
}
};
class StrategyFactory {
public:
virtual TaxStrategy* NewStrategy() = 0;
virtual ~StrategyFactory() {}
};
class CNFactory : public StrategyFactory {
public:
virtual TaxStrategy* NewStrategy() {
return new CNTax();
}
};
class USFactory : public StrategyFactory {
public:
virtual TaxStrategy* NewStrategy() {
return new USTax();
}
};
class DEFactory : public StrategyFactory {
public:
virtual TaxStrategy* NewStrategy() {
return new DETax();
}
};
class FRFactory : public StrategyFactory {
public:
virtual TaxStrategy* NewStrategy() {
return new FRTax();
}
};
class SalesOrder {
private:
TaxStrategy* strategy;
public:
SalesOrder(StrategyFactory* strategyFactory) {
this->strategy = strategyFactory->NewStrategy();
}
~SalesOrder() {
delete this->strategy;
}
double CalculateTax() {
//...
Context context;
double val = strategy->Calculate(context); //多态调用
//...
return val;
}
};
int main() {
StrategyFactory* strategy = new USFactory();//CNFactory();
SalesOrder* salesOrder = new SalesOrder(strategy);
cout << salesOrder->CalculateTax() << endl;
return 0;
}
代码来自网络——如有侵权联系我删除
点击这个跳转视频,尚硅谷-设计模式-策略模式,韩老师用的eclipse,java示例,视频很清楚代码如何写的,自己动手丰衣足食。
上面两个包括我举得例子思想都是一致的,就没有具体分析了,另外说明,尚硅谷韩老师在讲解这个例子的时候用的是java写的,使用了接口,而李老师使用C++讲解没有用接口(C++好像没接口),使用的继承,但是都是一个思想,我思考了一些时间后得出的结论。
THE END…