设计模式学习笔记之策略模式
2016-05-15 11:13
453 查看
策略模式
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
说明:
1、可以动态地改变对象的行为;
2、各个策略算法的平等性,各个策略算法在实现上是相互独立的,相互之间没有任何依赖的(由此,策略模式也可以描述为“策略算法是相同行为的不同实现”);
3、在运行期间,策略模式在某一时刻,只能使用一个具体的策略算法实现对象,虽然可以动态改变对象行为,但同时只能使用一个;
4、策略模式可以很简单的扩展新的实现算法。方法:先写一个策略算法来实现新的需求,然后在客户端使用时指定该实现算法即可;
5、多个if-elseif语句表达的就是一个平等的功能结构,你要么执行if,要不你就执行else,或者是elseif,这个时候,if块里面的实现和else块里面的实现从运行地位上来讲就是平等的。而策略模式就是把各个平等的具体实现封装到单独的策略实现类了,然后通过上下文来与具体的策略类进行交互。因此多个if-else语句可以考虑使用策略模式。
场景:
1、报价管理系统中,对于销售部门的人来说,要对不同的客户报不同的价格。如:对于普通用户或者新用户来说,报全价;对老客户报的价格,统一折扣5%;大客户报的价格,统一折扣10%。
实现:
A:定义策略接口
B:具体实现各个报价标准
C:价格类,上下文的实现
D:写个客户端进行测试
2、容错恢复机制。程序运行的时候,正常情况下应该按照某种方式来做,如果按照某种方式来做发生错误的话,系统并不会崩溃,也不会就此不能继续向下运行了,而是有容忍出错的能力,不但能容忍程序运行出现错误,还提供出现错误后的备用方案,也就是恢复机制,来代替正常执行的功能,使程序继续向下运行。
比如在一个系统中,所有对系统的操作都要有日志记录,而且这个日志还需要有管理界面,这种情况下通常会把日志记录在数据库里面,方便后续的管理,但是在记录日志到数据库的时候,可能会发生错误,比如暂时连不上数据库了,那就先记录在文件里面,然后在合适的时候把文件中的记录再转录到数据库中。
可以采用策略模式,把日志记录到数据库和日志记录到文件当作两种记录日志的策略,然后在运行期间根据需要进行动态的切换。
(1)先定义日志策略接口,很简单,就是一个记录日志的方法,示例代码如下:
(2)实现日志策略接口,先实现默认的数据库实现,假设如果日志的长度超过长度就出错,制造错误的是一个最常见的运行期错误,示例代码如下:
接下来实现记录日志到文件中去,示例代码如下:
(3)接下来定义使用这些策略的上下文,注意这次是在上下文里面实现具体策略算法的选择,所以不需要客户端来指定具体的策略算法了,示例代码如下:
(4)看看现在的客户端,没有了选择具体实现策略算法的工作,变得非常简单,故意多调用一次,可以看出不同的效果,示例代码如下:
参考资料:《Head First 设计模式》
http://www.uml.org.cn/sjms/201009092.asp
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
说明:
1、可以动态地改变对象的行为;
2、各个策略算法的平等性,各个策略算法在实现上是相互独立的,相互之间没有任何依赖的(由此,策略模式也可以描述为“策略算法是相同行为的不同实现”);
3、在运行期间,策略模式在某一时刻,只能使用一个具体的策略算法实现对象,虽然可以动态改变对象行为,但同时只能使用一个;
4、策略模式可以很简单的扩展新的实现算法。方法:先写一个策略算法来实现新的需求,然后在客户端使用时指定该实现算法即可;
5、多个if-elseif语句表达的就是一个平等的功能结构,你要么执行if,要不你就执行else,或者是elseif,这个时候,if块里面的实现和else块里面的实现从运行地位上来讲就是平等的。而策略模式就是把各个平等的具体实现封装到单独的策略实现类了,然后通过上下文来与具体的策略类进行交互。因此多个if-else语句可以考虑使用策略模式。
场景:
1、报价管理系统中,对于销售部门的人来说,要对不同的客户报不同的价格。如:对于普通用户或者新用户来说,报全价;对老客户报的价格,统一折扣5%;大客户报的价格,统一折扣10%。
实现:
A:定义策略接口
/** * 策略,定义计算报价算法的接口 */ public interface Strategy { /** * 计算应报的价格 * @param goodsPrice 商品销售原价 * @return 计算出来的,应该给客户报的价格 */ public double calcPrice(double goodsPrice); } |
/** * 具体算法实现,为新客户或者是普通客户计算应报的价格 */ public class NormalCustomerStrategy implements Strategy{ public double calcPrice(double goodsPrice) { System.out.println("对于新客户或者是普通客户,没有折扣"); return goodsPrice; } } |
/** * 具体算法实现,为老客户计算应报的价格 */ public class OldCustomerStrategy implements Strategy{ public double calcPrice(double goodsPrice) { System.out.println("对于老客户,统一折扣5%"); return goodsPrice*(1-0.05); } } |
/** * 具体算法实现,为大客户计算应报的价格 */ public class LargeCustomerStrategy implements Strategy{ public double calcPrice(double goodsPrice) { System.out.println("对于大客户,统一折扣10%"); return goodsPrice*(1-0.1); } } |
/** * 价格管理,主要完成计算向客户所报价格的功能 */ public class Price { /** * 持有一个具体的策略对象 */ private Strategy strategy = null; /** * 构造方法,传入一个具体的策略对象 * @param aStrategy 具体的策略对象 */ public Price(Strategy aStrategy){ this.strategy = aStrategy; } /** * 报价,计算对客户的报价 * @param goodsPrice 商品销售原价 * @return 计算出来的,应该给客户报的价格 */ public double quote(double goodsPrice){ return this.strategy.calcPrice(goodsPrice); } } |
public class Client { public static void main(String[] args) { //1:选择并创建需要使用的策略对象 Strategy strategy = new LargeCustomerStrategy (); //2:创建上下文 Price ctx = new Price(strategy); //3:计算报价 double quote = ctx.quote(1000); System.out.println("向客户报价:"+quote); } } |
比如在一个系统中,所有对系统的操作都要有日志记录,而且这个日志还需要有管理界面,这种情况下通常会把日志记录在数据库里面,方便后续的管理,但是在记录日志到数据库的时候,可能会发生错误,比如暂时连不上数据库了,那就先记录在文件里面,然后在合适的时候把文件中的记录再转录到数据库中。
可以采用策略模式,把日志记录到数据库和日志记录到文件当作两种记录日志的策略,然后在运行期间根据需要进行动态的切换。
(1)先定义日志策略接口,很简单,就是一个记录日志的方法,示例代码如下:
/** * 日志记录策略的接口 */ public interface LogStrategy { /** * 记录日志 * @param msg 需记录的日志信息 */ public void log(String msg); } |
/** * 把日志记录到数据库 */ public class DbLog implements LogStrategy{ public void log(String msg) { //制造错误 if(msg!=null && msg.trim().length()>5){ int a = 5/0; } System.out.println("现在把 '"+msg+"' 记录到数据库中"); } } |
/** * 把日志记录到文件 */ public class FileLog implements LogStrategy{ public void log(String msg) { System.out.println("现在把 '"+msg+"' 记录到文件中"); } } |
(4)看看现在的客户端,没有了选择具体实现策略算法的工作,变得非常简单,故意多调用一次,可以看出不同的效果,示例代码如下:
参考资料:《Head First 设计模式》
http://www.uml.org.cn/sjms/201009092.asp
相关文章推荐
- Android的Selector与Shape
- XenAPP6.5安装于部署(五)---Citrix AppCenter配置,发布应用
- AS使用备忘录
- 基于MATLAB的音频信号处理技术实现
- UML学习之初步总结
- hdu-5681 zxa and wifi(dp)
- RadioButton和CheckBox
- Java并发编程(1)一基础类和接口
- 制作网站二维码
- linux下用google protocol buffer(gpb)出现的编译问题------前后耗掉1个多小时
- C++中sizeof用法总结
- vim 编辑器配置
- 第十一周项目4——教师兼干部类
- shodan
- 第二次使用mapp. 数据结构是个好东西。。
- UML学习之用例图
- 1161 - Extreme GCD
- MySQL 数据库 ALTER命令讲解
- (总结)Nginx配置文件nginx.conf中文详解
- IE浏览器无法上网:该设备或资源(127.0.0.1)未设置为接受端口“16823”上的连接。