C++ 设计模式-策略模式

设计模式介绍

一、策略模式

1. 策略模式定义

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

2. 策略模式本质

分离算法,选择实现
策略算法是相同行为的不同实现

3. 策略模式结构和说明

(1) 结构

在这里插入图片描述
在这里插入图片描述

(2) 调用顺序

在这里插入图片描述

在这里插入图片描述

4. 策略模式适用情况

  1. 出现有许多相关的类,仅仅是行为有差别的情况下,可以使用策略模式来使用多个行为中的一个来配置一个类的方法,实现算法动态切换。
  2. 出现同一个算法,有很多不同实现的情况下,可以使用策略模式来把这些“不同的实现”实现成为一个算法的类层次。
  3. 需要封装算法中,有与算法相关数据的情况下,可以使用策略模式来避免暴露这些跟算法相关的数据结构。
  4. 出现抽象一个定义了很多行为的类,并且是通过多个if-lse语句来选择这些行为的情况下,可以使用策略模式来代替这些条件语句。

5. 策略模式优缺点

(1) 优点
  1. 定义一系列算法
    策略模式的功能就是定义一系列算法,实现让这些算法可以相互替换。所以会为这一系列算法定义公共的接口,以约束一系列算法要实现的功能。如果这一系列算法具有公共功能,可以把策略接口实现成为抽象类,把这些公共功能实现到父类中,对于这个问题,前面讲了三种处理方法,这里就不再啰嗦了。
  2. 避免多重条件语句
    根据前面的示例会发现,策略模式的一系列策略算法是平等的,是可以互换的,写在一起就是通过if-else结构来组织,如果此时具体的算法实现中又有条件语句,就构成了多重条件语句,使用策略模式能避免这样的多重条件语句。
  3. 更好的扩展性
    在策略模式中扩展新的策略实现非常容易,只要增加新的策略实现类,然后在使用策略的地方选择使用这个新的策略实现就可以了。
(2) 缺点
  1. 客户必须了解每种策略的不同
    策略模式也有缺点,比如让客户端来选择具体使用哪一个策略,这就需要客户了解所有的策略,还要了解各种策略的功能和不同,这样才能做出正确的选择,而且这样也暴露了策略的具体实现。
  2. 增加了对象数目
    由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
  3. 只适合扁平的算法结构
    策略模式的一系列算法地位是平等的,是可以相互替换的,事实上构成了一个扁平的算法结构,也就是在一个策略接口下,有多个平等的策略算法,就相当于兄弟算法。而且在运行时刻只有一个算法被使用,这就限制了算法使用的层级,使用的时候不能嵌套使用。

6. 相关模式

  1. 策略模式和状态模式
    这两个模式从模式结构上看是一样的,但是实现的功能却是不一样的。
    状态模式是根据状态的变化来选择相应的行为,不同的状态对应不同的类,每个状态对应的类实现了该状态对应的功能,在实现功能的同时,还会维护状态数据的变化。这些实现状态对应的功能的类之间是不能相互替换的。策略模式是根据需要或者是客户端的要求来选择相应的实现类,各个实现类是平等的,是可以相互替换的。另外策略模式可以让客户端来选择需要使用的策略算法;而状态模式一般是由上下文,或者是在状态实现类里面来维护具体的状态数据,通常不由客户端来指定状态。
  2. 策略模式和模板方法模式
    这两个模式可组合使用,如同前面示例的那样。
    模板方法重在封装算法骨架:而策略模式重在分离并封装算法实现
  3. 策略模式和享元模式
    这两个模式可组合使用。
    策略模式分离并封装出一系列的策略算法对象,这些对象的功能通常都比较单一,很多时候就是为了实现某个算法的功能而存在。因此,针对这一系列的、多个细粒度的对象,可以应用享元模式来节省资源,但前提是这些算法对象要被频繁地使用,如果偶尔用一次,就没有必要做成享元了。

策略模式示例代码

//示例1
#include <iostream>
#include <string>
#include <memory>

using namespace std;

//高层策略接口
class Strategy
{
public:
    virtual double CalcPrice(double  goodsPrice){return 0;}
};

//具体策略
//普通客户策略
class NormalCustomerStrategy : public Strategy
{
public:
    double CalcPrice(double  goodsPrice) override
    {
        //普通客户没有折扣
        std::cout<<"普通客户没有折扣"<<std::endl;
        return goodsPrice;
    }
};

//老客户策略
class OldCustomerStrategy : public Strategy
{
public:
    double CalcPrice(double  goodsPrice) override
    {
        //老客户 统一折扣5%
        std::cout<<"老客户折扣5%"<<std::endl;
        return goodsPrice * (1 - 0.05);
    }
};

//大客户策略
class LargeCustomerStrategy : public Strategy
{
    double CalcPrice(double  goodsPrice) override
    {
        //大客户 统一折扣10%
        std::cout<<"大客户折扣10%"<<std::endl;
        return goodsPrice * (1 - 0.1);
    }
};


//策略上下文
class Price
{
public:
    Price(Strategy* strategy) : pStrategy(strategy){}
    double Quote(double goodsPrice)
    {
        if(pStrategy != nullptr)
        {
            return pStrategy->CalcPrice(goodsPrice);
        }
        return 0;
    }
private:
    std::unique_ptr<Strategy> pStrategy {nullptr};
};
int main()
{
    {
        Price price(new NormalCustomerStrategy);
        double goodsPrice = price.Quote(100);
        std::cout<<"普通客户最终价:"<<goodsPrice<<std::endl;
    }

    {
        Price price(new OldCustomerStrategy);
        double goodsPrice = price.Quote(100);
        std::cout<<"老客户最终价:"<<goodsPrice<<std::endl;
    }

    {
        Price price(new LargeCustomerStrategy);
        double goodsPrice = price.Quote(100);
        std::cout<<"大客户最终价:"<<goodsPrice<<std::endl;
    }

    return 0;
}
//示例2
#include <iostream>
#include <string>
#include <memory>

using namespace std;

//策略模式扩展方式
//1.扩展上下文:通过继承上下文方式,然后在子类中添加相关数据
//2.扩展策略算法:在具体策略算法中添加相关数据

//高层策略接口
class PayStrategy
{
public:
    //virtual void Pay(PayContext* pPayContext){} //c++ 没有反射 不能直接传入context 然后获取上下文相关数据 适用于扩展方式1
    virtual void Pay(const std::string& user, double money){}
};

//具体策略
//人民币现金支付
class RMBCashStrategy : public PayStrategy
{
public:
    void Pay(const std::string& user, double money) override
    {
        std::cout<<user<<"人民币现金支付:"<<money<<std::endl;
    }
};

//美元支付
class DollarCashStrategy : public PayStrategy
{
public:
    void Pay(const std::string& user, double money) override
    {
        std::cout<<user<<"美元现金支付:"<<money<<std::endl;
    }
};

//RMB账户支付 扩展方式2
class RMBAccountStrategy : public PayStrategy
{
private:
    std::string account;
public:
    RMBAccountStrategy(std::string account) : account(account){}
public:
    void Pay(const std::string& user, double money) override
    {
        std::cout<<user<<"RMB账户"<<account<<"支付:"<<money<<std::endl;
    }
};

//策略上下文
class PayContext
{
private:
    std::string user;
    double money;

public:
    PayContext(std::string user, double money, PayStrategy* payStrategy) : user(user), money(money), pPayStrategy(payStrategy){}

public:
    void PayNow()
    {
        if(pPayStrategy != nullptr)
        {
            return pPayStrategy->Pay(this->user, this->money);
        }
    }

private:
    std::unique_ptr<PayStrategy> pPayStrategy {nullptr};
};


int main()
{
    {
        PayContext* payContext = new PayContext("张三", 100.0, new RMBCashStrategy());
        payContext->PayNow();
    }

    {
        PayContext* payContext = new PayContext("petter", 200.0, new DollarCashStrategy());
        payContext->PayNow();
    }

    {
        PayContext* payContext = new PayContext("李四", 300.0, new RMBAccountStrategy("123456789"));
        payContext->PayNow();
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值