大话设计模式2-策略模式(商场促销)
大话设计模式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 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.策略模式
策略模式定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。
说白了就是封装各个促销方法,定义一个支持所有算法的接口这一步我们已经完成了,其次再通过一个类维护指针。
两个作用:构造指针,根据具体的方法调用类算法完成多态,也就是说提供了接口。让子类中的方法与客户进行隔离,客户只知道。
#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
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函数也就是客户端中判断使用哪个算法,实现上也不好。我们想把判断过程封装起来,这时我们需要工厂来封装,接口过多的问题我们需要策略模式解决,所以需要结合两种模式。
由于我们客户希望只知道,所以要把工厂类搬到中,或者说由来实例合适的对象
以前的工厂类如下:
#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;}
};
以前的类如下
#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"
#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;
};
其余类和三个子类不变
main函数如下
#include"cashContext.h"
#include
using namespace std;int main()
{typeset s = ret;//满减cashContext* cc = new cashContext(s); double res = cc->getRes(600);cout << res;return 0;
}
可以看出客户只认识,通过传入的策略多态实现促销计算。
5.反思
策略模式可以将一系列算法封装起来,以相同的方式调用所有算法,减少了接口、每个算法也都有自己的类,可以单独进行调试。