C++设计模式(二)—策略模式

策略模式

它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

本文使用书中商场促销的例子,代码使用C++语言描述,代码存在的不足或问题有望各位指出。
(1)首先我们看一下策略模式的代码框架。
//策略模式算法简要
#include <iostream>
using namespace std;
//抽象算法类
class Strategy{
public:
    Strategy(){}
    virtual ~Strategy(){}
//算法方法
    virtual void AlgorithmInterface()=0;

};

//具体算法A
class ConcreteStrategyA: public Strategy
{
public:
//算法A实现发方法
    void AlgorithmInterface() override
    {
        cout << "算法A"<<endl;
    }

};

//具体算法B
class ConcreteStrategyB: public Strategy
{
public:
//具体B实现方法
    void AlgorithmInterface() override
    {
        cout<< "算法B" <<endl;
    }

};

//具体算法C
class ConcreteStrategyC: public Strategy
{
public:
//算法C实现方法
    void AlgorithmInterface() override
    {
        cout<<"算法C" <<endl;
    }
};

//上下文   注意C++中抽象基类不能实例化
class Context{
public:
    Context(Strategy *strategy)   //动态绑定,初始化时,传入具体的策略对象
    {
        this->strategy=strategy;
    }

  //上下文接口   根据具体的策略对象,调用其算法的方法
    void contextInterface()
    {
        strategy->AlgorithmInterface();
    }
private:
    Strategy *strategy;

};


int main()
{

  //由于实例化不同的策略,所以最终在调用context->contextInterface();时,所以获得的结果就不尽相同
    Context *context = nullptr;
    context = new Context(new ConcreteStrategyA());
    context->contextInterface();

    context = new Context(new ConcreteStrategyB());
    context->contextInterface();

    context = new Context(new ConcreteStrategyC());
    context->contextInterface();
    delete context;
    return 0;
}

个人理解就是使用了C++的动态绑定

(2)使用简单工厂模式来实现商场促销
//商场促销   简单工厂模式
#include <iostream>
#include <math.h>
#include <exception>
#include <map>
using namespace std;
//现金收费抽象类
class CashSuper
{
public:
    CashSuper(){}
    virtual ~CashSuper(){}
    virtual double acceptCash(double money) = 0;
};
//正常收费子类
class CashNormal : public CashSuper
{
    double acceptCash(double money) override
    {
        return money;
    }

};

//打折收费子类
class CashRebate: public CashSuper
{
public:
    CashRebate(string moneyRebate)
    {
        this->moneyRebate=atof(moneyRebate.c_str());
    }
    double acceptCash(double money) override
    {
        return money * moneyRebate;
    }
private:
    double moneyRebate = 1;
};


//返利收费子类
class CashReturn : public CashSuper
{
public:
    CashReturn (string moneyCondition, string moneyReturn): moneyConditon(0.0), moneyReturn(0.0)
    {
        this->moneyConditon=atof(moneyCondition.c_str());
        this->moneyReturn = atof(moneyReturn.c_str());
    }
    double acceptCash(double money) override
    {
        double result = money;
        if (money >= moneyConditon)
        {
            result = money - floor(money / moneyConditon) * moneyReturn;
        }
        return result;
    }
private:
    double moneyConditon;
    double moneyReturn;
};

//现金收费工厂类
class CashFactory
{
public:
    CashFactory(){}
    ~CashFactory(){}
    static CashSuper* createCashAccept (string type)
    {
        CashSuper* cs = nullptr;
//      static enum stringValue{normalCharge,fullBack,disCount};
        map<string,stringValue>mapStringValue;      //解决C++中switch不能使用string
        mapStringValue["正常收费"] = normalCharge;
        mapStringValue["满300返100"] = fullBack;
        mapStringValue["打8折"] = disCount;
        if(!mapStringValue.count(type))
            return cs;
        switch (mapStringValue[type])
        {
        case normalCharge:
            cs = new CashNormal();
            break;
        case fullBack:
            cs = new CashReturn("300", "100");
            break;
        case disCount:
            cs = new CashRebate("0.8");
            break;
        }
        return cs;
    }

private:
    enum stringValue{normalCharge,fullBack,disCount};
//  static map<string,stringValue>mapStringValue;  // 为什么不能在成员变量里调用
};

int main()
{
    CashSuper *cashSuper = nullptr;
    CashFactory cashFactory;
    double money,result;
    cout << "请输入金额:"<<endl;
    cin >> money;
    string type;
    cout << "请输入类型:(正常收费,满300返100,打8折)"<<endl;
    cin >> type;
    cashSuper = cashFactory.createCashAccept(type);
    if(cashSuper ==nullptr)
    {
        cout<<"输入有误或没有该优惠!\n"<<endl;
        return -1;
    }
    result = cashSuper->acceptCash(money);
    cout<<"应付金额:" << result << endl;
    delete cashSuper;
    return 0;
}

简单工厂模式虽然也能解决这个问题,但这个模式只能解决对象创建的问题,而且由于工厂本身包括了所有的收费方式,商场是可能经常地更改打折额度和返利额度,每次维护或扩展收费方式都要改动这个工厂,以致代码需要重新编译部署,所以用它不是最好的办法。

(3)使用策略模式实现商场促销
#include <iostream>
#include <math.h>
#include <exception>
#include <map>
using namespace std;
//现金收费抽象类
class CashSuper
{
public:
    CashSuper(){}
    virtual ~CashSuper(){}
    virtual double acceptCash(double money) = 0;
};
//正常收费子类
class CashNormal : public CashSuper
{
    double acceptCash(double money) override
    {
        return money;
    }

};

//打折收费子类
class CashRebate: public CashSuper
{
public:
    CashRebate(string moneyRebate): moneyRebate(1)
    {
        this->moneyRebate=atof(moneyRebate.c_str());
    }
    double acceptCash(double money) override
    {
        return money * moneyRebate;
    }
private:
    double moneyRebate;
};


//返利收费子类
class CashReturn : public CashSuper
{
public:
    CashReturn (string moneyCondition, string moneyReturn):moneyConditon(0.0), moneyReturn(0.0)
    {
        this->moneyConditon=atof(moneyCondition.c_str());
        this->moneyReturn = atof(moneyReturn.c_str());
    }
    double acceptCash(double money) override
    {
        double result = money;
        if (money >= moneyConditon)
        {
            result = money - floor(money / moneyConditon) * moneyReturn;
        }
        return result;
    }
private:
    double moneyConditon;
    double moneyReturn;
};

//使用策略模式实现
class CashContext
{
public:
    CashContext( CashSuper *cashSuper)
    {
        this->cs = cashSuper;
    }
    double getResult(double money)
    {
        return cs->acceptCash(money);
    }
private:
    CashSuper *cs;

};

int main ()
{
    CashContext *cashContext = nullptr;
    double money,result;
    cout << "请输入金额:"<<endl;
    cin >> money;
    string type;
    cout << "请输入类型:(正常收费,满300返100,打8折)"<<endl;
    cin >> type;
    enum stringValue{normalCharge,fullBack,disCount};
    map<string,stringValue>mapStringValue;      //解决C++中switch不能使用string
    mapStringValue["正常收费"] = normalCharge;
    mapStringValue["满300返100"] = fullBack;
    mapStringValue["打8折"] = disCount;
    if(!mapStringValue.count(type))
    {
        cout<<"输入有误或没有该优惠!\n"<<endl;
        return -1;
    }
    switch (mapStringValue[type])
    {
    case normalCharge:
        cashContext = new CashContext(new CashNormal());
        break;
    case fullBack:
        cashContext = new CashContext(new CashReturn("300", "100"));
        break;
    case disCount:
        cashContext = new CashContext(new CashRebate("0.8"));
        break;
    }
    result = cashContext->getResult(money);
    cout<<"应付金额:" << result << endl;
    delete cashContext;
    return 0;

}

虽然使用策略模式实现,但是main()函数感觉又回到原来的样子,所以我们可以采用简单工厂与策略模式融合的方式来达到目的。

(4)策略和简单工厂结合来实现商场促销
#include <iostream>
#include <math.h>
#include <exception>
#include <map>
using namespace std;
//现金收费抽象类
class CashSuper
{
public:
    CashSuper()
    virtual ~CashSuper(){}
    virtual double acceptCash(double money) = 0;
};
//正常收费子类
class CashNormal : public CashSuper
{
    double acceptCash(double money) override
    {
        return money;
    }

};

//打折收费子类
class CashRebate: public CashSuper
{
public:
    CashRebate(string moneyRebate): moneyRebate(1)
    {
        this->moneyRebate=atof(moneyRebate.c_str());
    }
    double acceptCash(double money) override
    {
        return money * moneyRebate;
    }
private:
    double moneyRebate;
};


//返利收费子类
class CashReturn : public CashSuper
{
public:
    CashReturn (string moneyCondition, string moneyReturn): moneyConditon(0.0), moneyReturn(0.0)
    {
        this->moneyConditon=atof(moneyCondition.c_str());
        this->moneyReturn = atof(moneyReturn.c_str());
    }
    double acceptCash(double money) override
    {
        double result = money;
        if (money >= moneyConditon)
        {
            result = money - floor(money / moneyConditon) * moneyReturn;
        }
        return result;
    }
private:
    double moneyConditon;
    double moneyReturn;
};

//策略与简单工厂结合

class CashContext
{
public:
    CashContext(){}
    ~CashContext()
    {
        delete cs;
    }
    CashContext (string type) :cs(nullptr)
    {
        map<string,stringValue>mapStringValue;      //解决C++中switch不能使用string
        mapStringValue["正常收费"] = normalCharge;
        mapStringValue["满300返100"] = fullBack;
        mapStringValue["打8折"] = disCount;
        if(!mapStringValue.count(type))
        {
            cerr<<"输入有误或没有该优惠!"<<endl;
            return;
        }
        switch (mapStringValue[type])
        {
        case normalCharge:
            cs = new CashNormal();
            break;
        case fullBack:
            cs = new CashReturn("300", "100");
            break;
        case disCount:
            cs = new CashRebate("0.8");
            break;
        }
    }
    double getResult (double money)
    {
        if(cs == nullptr)
        {
            return 0;
        }
        return cs->acceptCash(money);
    }
private:
    CashSuper *cs;
    enum stringValue{normalCharge,fullBack,disCount};
};

int main()
{
    double money,result=0;
    cout << "请输入金额:"<<endl;
    cin >> money;
    string type;
    cout << "请输入类型:(正常收费,满300返100,打8折)"<<endl;
    cin >> type;
    CashContext *cashContext = new CashContext(type);
    result = cashContext->getResult(money);
    if(result)
        cout<<"应付金额:" << result << endl;
    delete cs;
    return 0;

}

简单工厂模式需要客户端(main()函数)认识两个类,CashSuper和CashFactory,而策略模式与简单工厂结合的用法,客户端就只需要认识一个类CashContext就可以了,这使得具体的收费算法彻底与客户端分离,耦合更加降低。

策略模式分析:

策略模式是一种定义了一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThomasKUI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值