前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++设计模式 - 策略模式

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

原创
作者头像
开源519
修改2022-01-18 16:00:19
3470
修改2022-01-18 16:00:19
举报
文章被收录于专栏:开源519

策略模式

策略模式定义多种处理同一种场景的不同算法,这些算法可在不影响用户的情况下互相替换。

场景

应用场景

某会员制商场有两种级别会员:银卡会员、黄金会员,分别享有9折、8折购物优惠。同时不同的会员用户在生日当天购物,会赠送不同的生日礼物。

分析

场景比较简单,需要解决的问题是区分不同类型的顾客享有不同的权益(折扣和生日礼物)。

按照平常的编码习惯,通常会在需要区分用户等级的业务上加上if判断,实现不同等级顾客应享有的不同权益。这种方案能快速的解决实际问题,但是随着业务需要,商场又要引进更高逼格的会员类型,譬如白金会员、钻石会员等。此时,需要在散落在各处的业务代码上加上if补丁。这种做法会引来如下问题:

  • 业务代码散落各处,容易出现漏加if的情况,又难以验证。
  • 时间推移,if会越来越多,导致分支变多,代码走向模糊,影响代码维护。

解决方案

引入策略模式,将用户等级抽象,分别定义出用户所有的行为,不同等级的用户各自实现该等级应享有的权益。

类图

策略模式
策略模式

CShop:商场类。实现不同等级顾客的折扣结算、生日礼物等。持有CConsumer指针,根据需要指向具体的顾客实例(CCommonUser、CSilverUser、CGoldUser)。

CConsume:顾客抽象类。定义顾客所有的行为接口。

CCommonUser、CSilverUser、CGoldUser:具体顾客类。不同等级顾客实现有差异部分的接口。

效果

执行效果

代码语言:c++
复制
$ ./exe 

---------------------------------
 All Cost      : 1000.00.   
 User Type     : Common User.      
 Discount      : 1.00.   
 Actual Payment: 1000.00.   

---------------------------------
 All Cost      : 1000.00.   
 User Type     : Silver User.      
 Discount      : 0.90.   
 Actual Payment: 900.00.   

---------------------------------
 All Cost      : 1000.00.   
 User Type     : Gold User.      
 Discount      : 0.80.   
 Actual Payment: 800.00.   

客户端实现

代码语言:c++
复制
int main(int argc, char *argv[])
{
    CShop theShop;
    float cost = 1000.0;

    // 普通用户
    MAIN_LOG("\n---------------------------------\n");
    MAIN_LOG(" All Cost      : %0.2f.   \n"
             " User Type     : %s.      \n"
             " Discount      : %0.2f.   \n"
             " Actual Payment: %0.2f.   \n",
             cost,
             theShop.GetUserDesc().c_str(),
             theShop.GetCurrentDiscountRate(),
             theShop.GetRealPrice(cost));


    // 切换白银会员
    MAIN_LOG("\n---------------------------------\n");
    theShop.SetConsumer(COSUMER_SILVER);
    MAIN_LOG(" All Cost      : %0.2f.   \n"
             " User Type     : %s.      \n"
             " Discount      : %0.2f.   \n"
             " Actual Payment: %0.2f.   \n",
             cost,
             theShop.GetUserDesc().c_str(),
             theShop.GetCurrentDiscountRate(),
             theShop.GetRealPrice(cost));

    // 切换黄金会员
    MAIN_LOG("\n---------------------------------\n");
    theShop.SetConsumer(COSUMER_GOLD);
    MAIN_LOG(" All Cost      : %0.2f.   \n"
             " User Type     : %s.      \n"
             " Discount      : %0.2f.   \n"
             " Actual Payment: %0.2f.   \n",
             cost,
             theShop.GetUserDesc().c_str(),
             theShop.GetCurrentDiscountRate(),
             theShop.GetRealPrice(cost));

    return 0;
}

总结

  • 策略模式的实现原理比较简单,主要是改变持有指针的指向,即可实现不同方案的切换。更改为外部条件输入匹配对应的实例,便可以做到客户端代码无需改变自动切换不同方案的效果。
  • 满足开闭原则。当需增加策略时,只需要派生一个新的策略即可,而无需修改现有代码。相对以前的做法,更加安全快捷。
  • 在代码运行时,也可以动态切换策略。
  • 策略模式命令模式有点相像。两者的实现方式类似,应对的场景不同。策略模式针对的是同一个行为不同的算法实现;命令模式针对是一个命令对应一个解决的方法。
  • 全部源码可在公众号后台输入标题获取。

源码

商店类接口

代码语言:c++
复制
class CShop
{
public:
    CShop();

    ~CShop();

    std::string GetUserDesc() { return mConsumer->mUserDesc; }

    float GetRealPrice(float price);

    int BirthdayPresent();

    int SetConsumer(EConsumerType type);

    void SetCurrentDiscountRate(float rate);

    float GetCurrentDiscountRate();

private:
    CConsumer* mConsumer;
};

更新顾客类型

代码语言:c++
复制
int CShop::SetConsumer(EConsumerType type)
{
    switch (type)
    {
        case COSUMER_COMMON:
            mConsumer = CCommonUser::GetInstance();
        break;

        case COSUMER_SILVER:
            mConsumer = CSilverUser::GetInstance();
        break;

        case COSUMER_GOLD:
            mConsumer = CGoldUser::GetInstance();
        break;

        default:
        break;
    }

    if (NULL == mConsumer) {
        return -1;
    }

    return 0;
}

顾客类抽象接口

代码语言:c++
复制
class CConsumer
{
public:
    float mDiscountRate;
    std::string mUserDesc;

    CConsumer() : mDiscountRate(1.0)
    {

    }

    virtual ~CConsumer()
    {

    }

    void SetDiscountRate(float rate)
    {
        mDiscountRate = rate;
    }

    float GetDiscountRate()
    {
        return mDiscountRate;
    }

    float GetRealPrice(float price)
    {
        return mDiscountRate * price;
    }

    virtual int GetBirthdayPresent() = 0;
};

具体顾客类:黄金会员

代码语言:c++
复制
class CGoldUser : public CConsumer
{
public:
    CGoldUser();

    ~CGoldUser();

    static CGoldUser* GetInstance();

    int GetBirthdayPresent();
};

客户端接口

代码语言:c++
复制
int main(int argc, char *argv[])
{
    CShop theShop;
    float cost = 1000.0;

    // 普通用户
    MAIN_LOG("\n---------------------------------\n");
    MAIN_LOG(" All Cost      : %0.2f.   \n"
             " User Type     : %s.      \n"
             " Discount      : %0.2f.   \n"
             " Actual Payment: %0.2f.   \n",
             cost,
             theShop.GetUserDesc().c_str(),
             theShop.GetCurrentDiscountRate(),
             theShop.GetRealPrice(cost));


    // 切换白银会员
    MAIN_LOG("\n---------------------------------\n");
    theShop.SetConsumer(COSUMER_SILVER);
    MAIN_LOG(" All Cost      : %0.2f.   \n"
             " User Type     : %s.      \n"
             " Discount      : %0.2f.   \n"
             " Actual Payment: %0.2f.   \n",
             cost,
             theShop.GetUserDesc().c_str(),
             theShop.GetCurrentDiscountRate(),
             theShop.GetRealPrice(cost));

    // 切换黄金会员
    MAIN_LOG("\n---------------------------------\n");
    theShop.SetConsumer(COSUMER_GOLD);
    MAIN_LOG(" All Cost      : %0.2f.   \n"
             " User Type     : %s.      \n"
             " Discount      : %0.2f.   \n"
             " Actual Payment: %0.2f.   \n",
             cost,
             theShop.GetUserDesc().c_str(),
             theShop.GetCurrentDiscountRate(),
             theShop.GetRealPrice(cost));

    return 0;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 策略模式
  • 场景
  • 类图
  • 效果
  • 总结
  • 源码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档