S9. 策略模式

2022-01-09  本文已影响0人  开源519

策略模式

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

场景

应用场景

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

分析

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

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

解决方案

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

类图

策略模式

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

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

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

效果

执行效果

$ ./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.   

客户端实现

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

总结

源码

商店类接口

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

更新顾客类型

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

顾客类抽象接口

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

具体顾客类:黄金会员

class CGoldUser : public CConsumer
{
public:
    CGoldUser();

    ~CGoldUser();

    static CGoldUser* GetInstance();

    int GetBirthdayPresent();
};

客户端接口

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++ 设计模式 - 命令模式

开源519文章目录

上一篇 下一篇

猜你喜欢

热点阅读