2019/3/18 修改应用实例
2019/3/18 增加和模板方法的对比
策略模式定义一系列算法,将每个算法封装到具有公共接口的一系列策略类中,使它们可以相互替换,让算法可在不影响客户端的情况下发生变化。简单来说:准备一组算法,将每一个算法封装起来,让外部按需调用。
将算法的责任和本身进行解耦,使得:
算法可独立于使用外部而变化
外部方便根据外部条件选择不同策略来解决不同问题
策略模式仅仅封装算法(包括添加 & 删除),但策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定
优点
策略类之间可以互相替换,由于策略类都继承自同一个接口,所以使它们之间可以互相替换。
易于扩展,增加一个新的策略只需要添加一个具体的策略类即可,符合“开闭原则”(扩展开放,修改关闭)。
避免使用多重条件选择语句(if else),充分体现面向对象设计思想。
缺点
客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
将造成产生很多策略类(可以通过使用享元模式在一定程度上减少对象的数量)。
策略模式和模板方法
和模板方法区别在于,外部和算法之间多了一个中间层,中间层用于根据客户端的意愿,决定采用何种策略,这点可以看作模板方法模式的扩展;另外一个不同点在于,模板方法的设计目标是实现晚绑定,复用接口中的不可变部分,具体实现各个相似子类的可变部分,而策略模式的设计目标也是实现晚绑定,但是各个策略子类之间不一定有相同的部分,而是为了灵活的互相替换!
应用实例
情景:旅游区酒店需要接待来自各个国家的游客,所以需要按照不同国家的风味准备菜品。实现一系列策略类,每种口味的菜品抽象成一个策略类,这样就形成了一系列可供选择的策略类。为了灵活的选择其中某个策略(根据到店客人的口味准备相应的菜品),将这一系列策略抽象出一个共同的父类策略类。
//步骤1:定义抽象策略角色(CookStrategy):烹饪
class CookStrategy {
public:
virtual void Show() = 0;
};
//步骤2:定义具体策略角色(Concrete Strategy):针对不同国家的客人做不同的菜品
//为甲国客人准备A菜
class CookStrategyA : public CookStrategy {
public:
void Show() {
cout << "为甲国客人准备A菜" << endl;
}
};
//为乙国客人准备B菜
class CookStrategyB : public CookStrategy {
public:
void Show() {
cout << "为乙国客人准备B菜" << endl;
}
};
//为丙国客人准备C菜
class CookStrategyC : public CookStrategy {
public:
void Show() {
cout << "为丙国客人准备C菜" << endl;
}
};
接待客人的服务员需要知晓住客的国籍,从而为其准备不同口味的菜品,即构建对应的策略类。
// 步骤3:定义环境角色(Context):用于连接上下文,即为不同国家的住客提供不同的菜品
class Context_Waiter
{
//服务员需要知晓住客是哪个国家的(构造方法),使得让服务员根据传入的参数(国家)为其选择菜品
public:
void Waiter(Country country)
{
switch (country) {
//为甲国人准备A种套餐
case CountryJia:
strategy = new CookStrategyA();
break;
//为乙国人准备B种套餐
case CountryYi:
strategy = new CookStrategyB();
break;
//为丙国人准备C种套餐
case CountryBin:
strategy = new CookStrategyC();
break;
}
}
//向客人提供菜品
void WaiterShow() {
strategy->Show();
}
private:
CookStrategy *strategy; //持有抽象策略类的指针
};
最后在外部根据来人的国籍,准备不同的菜品套餐。策略模式的缺点就显现出来了,全世界有200多个国家,那么服务员需要熟悉所有国家名,也就是外部需要了解所有的策略。
int main()
{
Context_Waiter waiter;
//甲国客人来了,为其提供相应的菜品
cout << "甲国人:";
waiter.Waiter(CountryJia);
waiter.WaiterShow();
//乙国客人来了,为其提供相应的菜品
cout << "乙国人:";
waiter.Waiter(CountryYi);
waiter.WaiterShow();
//丙国客人来了,为其提供相应的菜品
cout << "丙国人:";
waiter.Waiter(CountryBin);
waiter.WaiterShow();
return 0;
}
运行结果: