策略模式:它定义了算法家族,分别封装起来,让他么之间可以互相替换。此模式让算法的变化,不会影响使用这些算法的客户。
在引出策略模式时,讨论了超市收银系统。可以将各种收费项目抽象成几种操作,比如正常收费、打折、返现、返积分。。。对打折来说,之所以可以这样进行抽象因为各种折扣之间存在着相互的联系,故将其抽象为一种。返现、返积分也类似。
算法本身是一种策略,这些算法可能随时被替换,这就是变化点,而封装变化点是面向对象一种很重要的思维方式。
策略模式是定义了一系列算法的方法,从概念上来看所有这些算法完成相同的工作,只是实现不同。它可以以相同的方式调用所有的算法,减少了各种算法类与使用它的算法类之间的耦合。
看代码:
//收费对象虚基类。
class SuperCashier
{
public:
double price;
int num;
public:
SuperCashier(double price,int num)
{
this->price=price;
this->num=num;
}
virtual double getTotalMoney()=0;
} ;
//正常收费
class Normal:public SuperCashier
{
public:
double discount;
public:
Normal(double price,int num)
:SuperCashier(price,num)
{
}
virtual double getTotalMoney()
{
return price*num;
}
} ;
//打折
class Discount:public SuperCashier
{
public:
double discount;
public:
Discount(double price,int num,double discount)
:SuperCashier(price,num)
{
this->discount=discount;
}
virtual double getTotalMoney()
{
return price*num*discount;
}
} ;
//返点
class ReturnPoint :public SuperCashier
{
public:
double conditionMoney;
double point;
public :
ReturnPoint(double price,double num,double cm,double rp)
:SuperCashier(price,num),conditionMoney(cm),point(rp)
{
}
virtual double getTotalMoney()
{
double total=price*num;
if(total>=conditionMoney)
{
double n=total/conditionMoney;
return point*n;
}
return 0;
}
};
//返现金
class ReturnMoney:public SuperCashier
{
public:
double conditionMoney;
double returnNum;
public:
ReturnMoney(double price,double num,double cm,double returnNum)
:SuperCashier(price,num),conditionMoney(cm)
{
this->returnNum=returnNum;
}
virtual double getTotalMoney()
{
double total=num*price;
if(total>=conditionMoney)
{
double n=total/conditionMoney;
return total-n*returnNum;
}
}
} ;
/************************************************************************/
/* 策略模式。 */
/***********************************************************************
class CashContext
{
public:
SuperCashier*sc;
public:
CashContext(SuperCashier*sc)
{
this->sc=sc;
}
double getResult()
{
return sc->getTotalMoney();
}
};
//在客户端进行判断。
int main(int argc,char**argv)
{
double price;
double num;
CashContext *cc;
while(1)
{
cout<<"1..正常收费。2..打折。3..返点 4..返利"<>ch;getchar();
switch(ch)
{
case 1:
{
cin>>price>>num;
cc=new CashContext(new Normal(price,num));
}
break;
case 2:
{
double discount;
cin>>price>>num>>discount;
cc=new CashContext(new Discount(price,num,discount));
}
break;
case 3:
{
double conditionMoney;
double returnPoint;
cin>>price>>num>>conditionMoney>>returnPoint;
cc=new CashContext(new ReturnPoint(price,num,conditionMoney,returnPoint));
}
break;
case 4:
{
double conditionMoney;
double returnMoney;
cin>>price>>num>>conditionMoney>>returnMoney;
cc=new CashContext(new ReturnMoney(price,num,conditionMoney,returnMoney));
}
break;
default:
break;
}
cout<getResult()<
/************************************************************************/
/* 策略模式与简单工厂模式结合,即将在main中的switch循环移到CashContext类中 */
/************************************************************************/
class CashContext
{
public:
int type;
double price;
double num;
double discount;
double conditionMoney;
double ret;
SuperCashier *sc;
public:
CashContext(int t,double price,int num,double discount)
:type(t)
{
this->price=price;
this->num=num;
this->discount=discount;
sc=NULL;
}
CashContext(int t,double price,int num)
:type(t)
{
this->price=price;
this->num=num;
sc=NULL;
}
CashContext(int t,double price,int num,double conditionMoney,double ret)
:type(t)
{
this->price=price;
this->num=num;
this->conditionMoney=conditionMoney;
this->ret=ret;
sc=NULL;
}
double getResult()
{
switch(type)
{
case 1://正常收费
{
sc=new Normal(price,num);
}
break;
case 2://打折
{
sc=new Discount(price,num,discount);
}
break;
case 3://返点
{
sc=new ReturnPoint(price,num,conditionMoney,ret);
}
break;
case 4://返现
{
sc=new ReturnPoint(price,num,conditionMoney,ret);
}
break;
default:
break;
}
return sc->getTotalMoney();
}
};
int main(int argc,char**argv)
{
CashContext *cc;
double price,num,discount,conditionMoney,ret;
cin>>price>>num;
cc=new CashContext(1,price,num);
cout<getResult()<>price>>num>>discount;
cc=new CashContext(2,price,num,discount);
cout<getResult()<>price>>num>>conditionMoney>>ret;
cc=new CashContext(3,price,num,conditionMoney,ret);
cout<getResult()<>price>>num>>conditionMoney>>ret;
cc=new CashContext(4,price,num,conditionMoney,ret);
cout<getResult()<
此处觉得有不妥,一旦超市推出另外一些活动,CashContext类中用于switch判断的代码就要修改,程序需要重新编译。这在实际应用中是不可能的。第二章的最后提了一下使用映射可以解决这个问题。但不知映射为何物,拭目以待吧
注:此处实现的收费对象类,比书上的多实现了返点类。关于此类不知应该将其归为哪一部分,暂将其放入收费对象类中。但觉得不应该与收费对象类放在一起,应该有另外一个类处理返点。毕竟积分信息的管理对于大型超市来说也是很重要的一部分。