设计模式-策略模式
来源:互联网 发布:淘宝差评可以申诉吗 编辑:程序博客网 时间:2024/06/16 10:53
序言
设计模式是编程所要掌握的重要技能,其实这之前这些模式都看过相关例子源代码,但是时间一久,每次别人问起,什么是策略模式,或者其他。总是说不清道不明,后来干脆说我忘记了。后来仔细想来,其实我当初根本不知道什么是策略模式,只是看了定义,看了软件结构,看了例子代码。然而这些远远不够,前辈们总结下来的精华,怎么可能在短短几篇博客或者几页书就能完全掌握呢。深挖其中的精髓,并且能够自己设计出来,才应该是真正的掌握。固然为了模式,而去强行写设计模式,这听起来似乎有点不妥,但是强行写设计模式都写不出来,何谈你懂的设计模式呢。
定义
封装一系列算法,并在内部实现可以互相替换,可以让算法独立于使用者而变化。简单点说就是:一家商场,会针对客户的消费等级比如普通客户,高级客户,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; }else{discount += 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; }else{discount += 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 代码的文章中再次对策略模式进行实例分析。
- 设计模式-策略模式
- 设计模式:策略模式
- 设计模式-策略模式
- 设计模式 - 策略模式
- 设计模式-策略模式
- 设计模式-----策略模式
- 设计模式 策略模式
- 设计模式-策略模式
- 设计模式-【策略模式】
- 设计模式-----策略模式
- 设计模式-策略模式
- 设计模式--策略模式
- 设计模式- 策略模式
- 设计模式- 策略模式
- 设计模式------策略模式
- 设计模式--策略模式
- 设计模式-策略模式
- 设计模式--策略模式
- JAVA以后要走的路
- 使用ng-animate为网页增加动画效果
- 数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(二)之SQL解析
- 基础复习02
- php处理与H5对接时的跨域问题
- 设计模式-策略模式
- MySQL数据库还原
- linux 开机运行命令
- hadoop2.x中hadoop—core.jar包使用
- 分割回文串II
- 《互联网信贷风险与大数据》读书笔记(四)
- 自定义控件——第一行代码3.4.2
- SUMO-0.30.0概要记录
- 类的公有继承