策略模式
它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
本文使用书中商场促销的例子,代码使用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就可以了,这使得具体的收费算法彻底与客户端分离,耦合更加降低。
策略模式分析:
策略模式是一种定义了一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。