大话设计模式2-策略模式
1.需求:商场促销
商场有不同的促销情况,可以打折、满减以及不促销
2.简单工厂实现
简单工厂实现可以①设计一个收费抽象类,交给子类去重写
#pragma once
class cashSuper {
public :
virtual double acceptCash(double money)
{
return money;
}
};
②再定义正常收费、满减、打折三个子类。
正常收费
#pragma once
#include"cashSuper.h"
class cashNomal :public cashSuper {
public:
double acceptCash(double money)
{
return money;
}
};
打折
#pragma once
#include"cashSuper.h"
class cashRebate :public cashSuper {
public:
cashRebate(double bate = 1):rebate(bate){}
double acceptCash(double money){
return money*rebate;
}
private:
double rebate;
};
满减
构造时需要两个参数分别是满减条件以及满减金额
#pragma once
#include"cashSuper.h"
class cashReturn :public cashSuper {
private:
double moneycond;
double moneyret;
public:
cashReturn(double cond,double ret):moneycond(cond),moneyret(ret){}
double acceptCash(double money)
{
double res = money;
if (money > moneycond)
res = money - int((money / moneycond))* moneyret;
return res;
}
};
③之后是工厂类,用来实例化合适的对象
#pragma once
#include"cashNormal.h"
#include"cashRebate.h"
#include"cashReturn.h"
#include"cashSuper.h"
using namespace std;
enum typeset{nomal,rebate,ret};
class moneyFactory {
public:
cashSuper* createCash(typeset type) {
cashSuper* cs = nullptr;
switch (type)
{
case nomal:
cs = new cashNomal();
break;
case rebate:
cs = new cashRebate(0.8);
break;
case ret:
cs = new cashReturn(300,100);
break;
}
return cs;
}
};
④main函数
#include"moneyFactory.h"
#include<iostream>
int main()
{
double res;
cashSuper* su;
moneyFactory factory;
su = factory.createCash(nomal);
res = su->acceptCash(600);
cout << res << endl;
su = factory.createCash(rebate);
res = su->acceptCash(600);
cout << res << endl;
su = factory.createCash(ret);
res = su->acceptCash(600);
cout << res << endl;
return 0;
}
输入为600,在正常、打八折、满300减100情况下输出:
3.策略模式
策略模式定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。
说白了就是封装各个促销方法,定义一个支持所有算法的接口cashSuper
这一步我们已经完成了,其次再通过一个cashContext
类维护cashSuper
指针。
cashContext
两个作用:构造cashSuper
指针,根据具体的方法调用cashSuper
类算法完成多态,也就是说提供了接口。让cashSuper
子类中的方法与客户进行隔离,客户只知道cashContext
。
#pragma once
#include"cashSuper.h"
class cashContext {
public:
cashContext(cashSuper *super): su(super){}
double getRes(double money) {
return su->acceptCash(money);
}
private:
cashSuper* su;
};
正常收费、满减、打折三个子类不变。
正常收费
#pragma once
#include"cashSuper.h"
class cashNomal :public cashSuper {
public:
double acceptCash(double money)
{
return money;
}
};
打折
#pragma once
#include"cashSuper.h"
class cashRebate :public cashSuper {
public:
cashRebate(double bate = 1):rebate(bate){}
double acceptCash(double money){
return money*rebate;
}
private:
double rebate;
};
满减
构造时需要两个参数分别是满减条件以及满减金额
#pragma once
#include"cashSuper.h"
class cashReturn :public cashSuper {
private:
double moneycond;
double moneyret;
public:
cashReturn(double cond,double ret):moneycond(cond),moneyret(ret){}
double acceptCash(double money)
{
double res = money;
if (money > moneycond)
res = money - int((money / moneycond))* moneyret;
return res;
}
};
#pragma once
class cashSuper {
public :
virtual double acceptCash(double money)
{
return money;
}
};
main函数实现
#include"cashContext.h"
#include"cashNormal.h"
#include"cashRebate.h"
#include"cashReturn.h"
#include"cashSuper.h"
#include<iostream>
using namespace std;
enum typeset { nomal, rebate, ret };
int main()
{
typeset type = ret;
cashContext* cc = nullptr;
switch (type)
{
case nomal:
cc = new cashContext(new cashNomal());
break;
case rebate:
cc = new cashContext(new cashRebate(0.8));
break;
case ret:
cc = new cashContext(new cashReturn(300, 100));
break;
}
double res = cc->getRes(600);
cout << res;
return 0;
}
4.策略模式与简单工厂的结合
我们先分析工厂模式与策略模式的缺点。
如下图工厂模式中,我们需要工厂类和现金消费类两方协助才能够完成促销计算,增加了接口,维护较复杂。
而策略模式虽然只需要一个上下文接口,但是在main函数也就是客户端中判断使用哪个算法,实现上也不好。我们想把判断过程封装起来,这时我们需要工厂来封装,接口过多的问题我们需要策略模式解决,所以需要结合两种模式。
由于我们客户希望只知道cashContext
,所以要把工厂类搬到cashContext
中,或者说由cashContext
来实例合适的对象
以前的工厂类如下:
#include"cashReturn.h"
#include"cashSuper.h"
using namespace std;
enum typeset{nomal,rebate,ret};
class moneyFactory {
public:
cashSuper* createCash(typeset type) {
cashSuper* cs = nullptr;
switch (type)
{
case nomal:
cs = new cashNomal();
break;
case rebate:
cs = new cashRebate(0.8);
break;
case ret:
cs = new cashReturn(300,100);
break;
}
return cs;
}
};
以前的cashContext
类如下
#pragma once
#include"cashSuper.h"
class cashContext {
public:
cashContext(cashSuper *super): su(super){}
double getRes(double money) {
return su->acceptCash(money);
}
private:
cashSuper* su;
};
合并,cashContext
依旧维护抽象计算cashSuper
的指针,此外还负责实例化具体策略。
#pragma once
#include"cashSuper.h"
#include"cashNormal.h"
#include"cashRebate.h"
#include"cashReturn.h"
enum typeset { nomal, rebate, ret };
class cashContext {
public:
cashContext(typeset type)
{
switch (type)
{
case nomal:
cs = new cashNomal();
break;
case rebate:
cs = new cashRebate(0.8);
break;
case ret:
cs = new cashReturn(300, 100);
break;
}
}
double getRes(double money)
{
return cs->acceptCash(money);
}
private:
cashSuper* cs;
};
其余cashSuper
类和三个子类不变
main函数如下
#include"cashContext.h"
#include<iostream>
using namespace std;
int main()
{
typeset s = ret;//满减
cashContext* cc = new cashContext(s);
double res = cc->getRes(600);
cout << res;
return 0;
}
可以看出客户只认识cashContext
,通过传入的策略多态实现促销计算。
5.反思
策略模式可以将一系列算法封装起来,以相同的方式调用所有算法,减少了接口、每个算法也都有自己的类,可以单独进行调试。