[设计模式] 2.Strategy(策略模式)

本文深入探讨了策略模式的概念,通过一个旅游区酒店为不同国家游客准备菜品的实例,展示了策略模式如何封装一系列算法并允许它们在运行时互换,强调了其在避免条件语句和易于扩展方面的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

运行结果:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值