设计模式-策略模式
Posted 哇小明
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-策略模式相关的知识,希望对你有一定的参考价值。
序言
设计模式是编程所要掌握的重要技能,其实这之前这些模式都看过相关例子源代码,但是时间一久,每次别人问起,什么是策略模式,或者其他。总是说不清道不明,后来干脆说我忘记了。后来仔细想来,其实我当初根本不知道什么是策略模式,只是看了定义,看了软件结构,看了例子代码。然而这些远远不够,前辈们总结下来的精华,怎么可能在短短几篇博客或者几页书就能完全掌握呢。深挖其中的精髓,并且能够自己设计出来,才应该是真正的掌握。固然为了模式,而去强行写设计模式,这听起来似乎有点不妥,但是强行写设计模式都写不出来,何谈你懂的设计模式呢。
定义
封装一系列算法,并在内部实现可以互相替换,可以让算法独立于使用者而变化。简单点说就是:一家商场,会针对客户的消费等级比如普通客户,高级客户,vip客户对商品进行不同的打折情况。打折情况就是算法的封装,比如vip打折80%,普通客户打折95%。
软件结构
Strategy 类作为算法的一个容器,也就是所有具体算法的父类,定义一系列通用接口,一般这个类为虚基类,算法接口定义为纯虚函数,实例话必须通过子类来实现。
CustomerClient这个类事面向用户的客户端,这个类的构造函数需要传递一个Strategy 类型的参数,一般这里都会把具体要调用的算法子类的实例作为参数,传进去。原因就是会在doAction中去调用访问子类算法的具体方法。
ConcretStrategy 为具体的算法实现类,一般都会有多个存在,不同的算法子类可以算是一个策略。这里面会实现父类的公共接口。
简单的代码框架实现:
/*
*策略封装类,必须定义一个纯虚公共接口,子类中需要实现这个接口。
*/
class Strategy
public:
virtual ~Strategy()
virtual void AlgrithmInterface() = 0;
protected:
Strategy()//声明为protected属性,是为了防止客户实例化这个类
;
/*
*具体策略算法,实现父类的接口
*/
class ConcretStrategyA : public Strategy
public:
ConcretStrategyA()
virtual ~ConcretStrategyA()
virtual void AlgrithmInterface()
cout<<"This is ConcretStrategyA interface!"<<endl;
;
/*
*具体策略算法,实现父类的接口
*/
class ConcretStrategyB : public Strategy
public:
ConcretStrategyB()
virtual ~ConcretStrategyB()
virtual void AlgrithmInterface()
cout<<"This is ConcretStrategyB interface!"<<endl;
;
class CustomerClient
public:
CustomerClient(Strategy *stra)
_stra = stra;//客户端初始化时必须指定要调用的算法
virtual ~CustomerClient()
void doAction()
if(_stra != NULL)
_stra->AlgrithmInterface();
private:
Strategy *_stra;
;
//测试程序
#include <iostream>
using namespace std;
int main()
cout<<"策略设计模式例子!"<<endl;
Strategy *straA = new ConcretStrategyA();
Strategy *straB = new ConcretStrategyB();
CustomerClient *clientA = new CustomerClient(straA);
CustomerClient *clientB = new CustomerClient(straB);
clientA->doAction();
clientB>doAction();
//更简洁的写法
/*
CustomerClient *clientA = new CustomerClient(new ConcretStrategyA());
clientA->doAction();
CustomerClient *clientB = new CustomerClient(new ConcretStrategyB());
client->doAction();
*/
delete starA;
delete clientA;
delete starB;
delete clientB;
return 0;
如上述代码所示,要实现策略模式,至少包含三个类的实现。
上述代码应该可以作为所有策略模式代码的一个基本框架,客户端只需要考虑到CustomerClient的实现就可以,这个类里面不会有具体算法的实现细节,它通过一个保存在类中的实例化的策略封装类(Strategy)去调用具体的算法,而客户端只要明确的把要调用的具体算法的实例作为参数(new ConcretStrategyA())传给CustomerClient的构造函数,虽然每个具体算法的类都不一样,但是他们都有共同的父类Strategy,而CustomerClient构造函数的参数就是Strategy类型的,这就是C++中多态的作用了。
在什么场合下要使用策略模式?
(以下内容从Gof的设计模式书中总结而来)
- 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
- 需要使用一个算法的不同变体,当这些算法的变体实现为一个算法的类层次的时候,可以使用策略模式。
- 一个类定义多种行为,并且这些行为在这个类的操作中以多个条件语句或者switch形式存在,可以考虑使用策略模式。
具体应用例子
正如文章开头所提的商场针对客户的等级,而对衣服的不同打折策略这个情况,设计一个程序来满足这种情况。
先设计程序的UML图结构:
程序设计简单思路:
首先三个等级的客户打折情况会在三个分区,不会有交集,我们假设有year,buys,costs,birthday,new_styles这五个属性会影响最后的打折情况,也就是说同样为高级客户也有可能会出现最后的折扣不一样的情况,但是总体都属于高级用户打折区间内。但是每个类型的客户并不一定会同时被这五个属性所影响,比如我们设定:
普通客户受year,new_styles影响
高级客户受year,buys,new_styles影响
VIP客户受costs,birthday影响。
这个时候在设计公共接口的时候,就要全方位考虑到各种影响三种策略的属性,也就是让接口的扩展性更强,包含所有情况,至于子类具体算法要不要使用时后面算法的事,作为父类要考虑到所有情况。
代码实现:
/*
*策略封装类,必须定义一个纯虚公共接口,子类中需要实现这个接口。
*/
class DiscountStrategy
public:
virtual ~DiscountStrategy()
virtual int computeDiscountPrice(int year,int buys, int all_cost,bool birthday, bool new_styles) = 0;
static int vip_discount[2];
static int higher_discount[2];
static int normal_discount[2];
protected:
DiscountStrategy()//声明为protected属性,是为了防止客户实例化这个类
;
//定义三种客户的打折区间
int DiscountStrategy::vip_discount[2]=70,80;
int DiscountStrategy::higher_discount[2]=80,90;
int DiscountStrategy::normal_discount[2]=90,100
/*
*普通客户策略算法,实现父类的接口
*/
class NormalDiscount : public DiscountStrategy
public:
NormalDiscount()
virtual ~NormalDiscount()
virtual int computeDiscountPrice(int year,int buys, int all_cost,bool birthday, bool new_styles)
cout<<"This is NormalDiscount interface!"<<endl;
int discount = 0;
if(year < 4 && year >2)
discount += 2;
elsediscount += 3;
if(!new_styles)discount += 3;
return normal_discount[1]-discount;
;
/*
*高级客户策略算法,实现父类的接口
*/
class HigherDiscount : public DiscountStrategy
public:
HigherDiscount()
virtual ~HigherDiscount()
virtual int computeDiscountPrice(int year,int buys, int all_cost,bool birthday, bool new_styles)
cout<<"This is HigherDiscount interface!"<<endl;
int discount = 0;
if(year < 4 && year >2)
discount += 2;
elsediscount += 3;
if(buys > 20)discount += 2;
if(!new_styles)discount += 3;
return higher_discount[1]-discount;
;
/*
*VIP客户策略算法,实现父类的接口
*/
class VIPDiscount : public DiscountStrategy
public:
VIPDiscount()
virtual ~VIPDiscount()
virtual int computeDiscountPrice(int year,int buys, int all_cost,bool birthday, bool new_styles)
cout<<"This is VIPDiscount interface!"<<endl;
int discount = 0;
if(all_cost > 5000)
discount += 2;
else if(all_cost >2000)
discount += 1;
if(birthday)discount += 2;
return vip_discount[1]-discount;
;
class CustomerClient
public:
CustomerClient(DiscountStrategy *stra)
_stra = stra;//客户端初始化时必须指定要调用的算法
virtual ~CustomerClient()
void setInfomation(int years, int buys, int costs, bool birthday,bool new_styles)
_year = years;
_buys = buys;
_all_cost = costs;
_birthday = birthday;
_new_styles = new_styles;
void Discount()
if(_stra != NULL)
_stra->computeDiscountPrice(_year,_buys,_all_costs,_birthday,_new_styles);
private:
DiscountStrategy *_stra;
int _year;//用户的购物年龄
int _buys;//用户所买物品的数量
int _all_cost;//用户一共花的钱
bool _birthday;//当月是否是用户的生日
bool _new_styles;//所买物品是否是新上市
;
//主程序
#include <iostream>
using namespace std;
int main()
int customer_type;
int year;
int buys;
int costs;
bool birthday;
bool new_styles;
while(true)
cout<<"Please Input the Customer's type(normal=1,higher=2,vip=3)"<<endl;
cin>>customer_type;
cout<<"Input years:"<<endl;
cin>>year;
cout<<"Input buys:"<<endl;
cin>>buys;
cout<<"Input costs:"<<endl;
cin>>costs;
cout<<"Input birthday(0 yes, 1 no):"<<endl;
cin>>birthday;
cout<<"Input new_styles(0 yes,1 no):"<<endl;
cin>>new_styles;
if(customer_type == 1)
CustomerClient *client = new CustomerClient(new NormalDiscount());
if(customer_type == 2)
CustomerClient *client = new CustomerClient(new HigherDiscount());
//此处省略vip了.....
client->setInfomation(year, buys, costs, birthday,new_styles);
client->Discount();
return 0;
策略模式有个确定想必看了上面程序会发觉:
1.客户必须了解不同的策略,得知道这些策略有何不同,才会知道如何选择这些策略。此时可能不得不向客户暴露具体的实现问题,因此当这些不同行为变体于客户相关的行为时,才需要使用strategy模式
2.strategy和CustomerClient之间的通讯开销,正如前面所说不同的策略所需要的信息可能不一样,但是每次实例化具体策略的时候都要把这些信息传递过去,即使一个简单的策略不需要任何信息,也会有客户端这边初始化了一些永远也用不到的参数。
策略模式到此为止,后续会在分析android framework 代码的文章中再次对策略模式进行实例分析。
以上是关于设计模式-策略模式的主要内容,如果未能解决你的问题,请参考以下文章