一、策略模式--小伟带你学设计模式
2016-05-23 11:13
183 查看
一、策略模式定义:
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
二、组成部分:
1、环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用,可以定义一个接口来让Strategy访问他的数据。(持有一个策略类的引用,最终给客户端调用)。
2、抽象策略类(Strategy):定义所有支持的算法的公共接口,Context使用这个接口来调用某ConcreteStrategy定义的算法。
3、具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
三、设计原则(只是一部分设计原则,所有设计模式都通用):
1、找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。(把会变化的部分取出并“封装“起来,好让其他部分不会受到影响)。
2、针对接口编程,而不是针对实现编程。“针对接口编程”真正的意思是“针对超类型编程”。
接口只是一个”概念“,也是一种Java的Interface构造,你可以在不涉及Java Interface情况下,”针对接口编程“,关键就在于多态,利用多态,程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上,”针对超类型编程“这句话,可以明确说成”变量的声明类型应该是超类型,通常是一个抽象类或者是一个接口“。
3、多用组合,少用继承。(当你将两个类结合起来使用就是组合)。
四、应用场景:
1、多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2、需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其他方式来实现。
3、对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
五、优缺点:
优点:
1、策略模式提供了管理相关的算法族的办法,策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。
2、策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就有可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起,决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能在独立演化。继承使得动态改变算法或行为变得不可能。
3、使用策略模式可以避免使用多重条件转移语句,多重转移语句不移维护,他把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点:
1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类,这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类,换言之:策略模式只适用于客户端知道所有的算法或行为的情况。(不得不暴露出算法或行为的具体实现)
2、策略模式造成很多的策略类,每个具体策略类都会产生一个新类,有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用,换言之,可以使用享元模式来减少对象的数量。
六、具体的Demo:
需求:
狗,有的狗带看家本领,有的狗不带看家本领,有的狗能拿老鼠,有的狗能和老鼠一起玩耍,有的狗完全不理会老鼠。
思路:
我们首先需要找到哪些是可变化的动作行为,需要独立出来。
不难发现:看家本领和能否抓老鼠是两个可变化的行为。
1、我们首先要写个超类,这个超类里面有个最基本的方法yell(叫)
2、我们要将第一个“看家本领”这个可变的动作行为抽取出一个接口。
3、写两个实现类去实现2步骤中的接口,一个实现成带看家本领,一个实现成不带看家本领的。
4、同理我们需要将“是否能抓老鼠”这个可变的动作行为抽取成一个接口,并有三个实现类。
我们可以把每个动作行为都看成一个“算法”,这样我们就完成了策略模式的第一个概念:“定义了算法族,分别封装起来”
5、下面的工作就是需要在超类中加上那两个接口的引用变量。并给予set方法(目的是为了让子狗能方便的在运行时动态的改变行为)
6、接下来的工作就简单了,声明一大堆狗的子类,各自实现各自的动作行为即可。
这样就能使项目十分带有弹性,完全达到了“让算法的变化独立于使用算法的客户”
代码:
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
二、组成部分:
1、环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用,可以定义一个接口来让Strategy访问他的数据。(持有一个策略类的引用,最终给客户端调用)。
2、抽象策略类(Strategy):定义所有支持的算法的公共接口,Context使用这个接口来调用某ConcreteStrategy定义的算法。
3、具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
三、设计原则(只是一部分设计原则,所有设计模式都通用):
1、找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。(把会变化的部分取出并“封装“起来,好让其他部分不会受到影响)。
2、针对接口编程,而不是针对实现编程。“针对接口编程”真正的意思是“针对超类型编程”。
接口只是一个”概念“,也是一种Java的Interface构造,你可以在不涉及Java Interface情况下,”针对接口编程“,关键就在于多态,利用多态,程序可以针对超类型编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上,”针对超类型编程“这句话,可以明确说成”变量的声明类型应该是超类型,通常是一个抽象类或者是一个接口“。
3、多用组合,少用继承。(当你将两个类结合起来使用就是组合)。
四、应用场景:
1、多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2、需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其他方式来实现。
3、对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
五、优缺点:
优点:
1、策略模式提供了管理相关的算法族的办法,策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。
2、策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就有可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起,决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能在独立演化。继承使得动态改变算法或行为变得不可能。
3、使用策略模式可以避免使用多重条件转移语句,多重转移语句不移维护,他把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点:
1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类,这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类,换言之:策略模式只适用于客户端知道所有的算法或行为的情况。(不得不暴露出算法或行为的具体实现)
2、策略模式造成很多的策略类,每个具体策略类都会产生一个新类,有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用,换言之,可以使用享元模式来减少对象的数量。
六、具体的Demo:
需求:
狗,有的狗带看家本领,有的狗不带看家本领,有的狗能拿老鼠,有的狗能和老鼠一起玩耍,有的狗完全不理会老鼠。
思路:
我们首先需要找到哪些是可变化的动作行为,需要独立出来。
不难发现:看家本领和能否抓老鼠是两个可变化的行为。
1、我们首先要写个超类,这个超类里面有个最基本的方法yell(叫)
2、我们要将第一个“看家本领”这个可变的动作行为抽取出一个接口。
3、写两个实现类去实现2步骤中的接口,一个实现成带看家本领,一个实现成不带看家本领的。
4、同理我们需要将“是否能抓老鼠”这个可变的动作行为抽取成一个接口,并有三个实现类。
我们可以把每个动作行为都看成一个“算法”,这样我们就完成了策略模式的第一个概念:“定义了算法族,分别封装起来”
5、下面的工作就是需要在超类中加上那两个接口的引用变量。并给予set方法(目的是为了让子狗能方便的在运行时动态的改变行为)
6、接下来的工作就简单了,声明一大堆狗的子类,各自实现各自的动作行为即可。
这样就能使项目十分带有弹性,完全达到了“让算法的变化独立于使用算法的客户”
代码:
package strategy; /** * * 描述:由于是超类,只是提供一些动作行为,可变化的“算法”已经提取出去,所以设为抽象类最为合适 * @author chentongwei * @date 2016年5月23日上午11:39:15 * @version 1.0 */ public abstract class Dog { //是否带有看家本领 protected Home isWacthHome; //是否能抓老鼠 protected Mouse isFetchMouse; /** * 将看家本领委托给接口处理 */ protected void watchHome () { isWacthHome.isWatchHome(); } /** * 将抓老鼠本领委托给接口处理 */ protected void fetchMouse () { isFetchMouse.isFetchMouse(); } //方便动态运行时改变dog子类的行为 public void setIsWacthHome(Home isWacthHome) { this.isWacthHome = isWacthHome; } //方便动态运行时改变dog子类的行为 public void setIsFetchMouse(Mouse isFetchMouse) { this.isFetchMouse = isFetchMouse; } /** * * 描述:狗的通用方法--叫 * @author chentongwei * @date 2016年5月23日上午11:44:40 * 修改人以及修改时间: * 修改内容: * @version 1.0 */ protected void yell() { System.out.println("wang wang ... "); } }
package strategy; /** * * 描述:是否能看守家园的接口 * @author chentongwei * @date 2016年5月23日上午11:43:26 * @version 1.0 */ public interface Home { /** * * 描述:是否能看守家园的“算法” * @author chentongwei * @date 2016年5月23日上午11:43:57 * 修改人以及修改时间: * 修改内容: * @version 1.0 */ public void isWatchHome(); }
package strategy; /** * * 描述:可以看守家园的接口 * @author chentongwei * @date 2016年5月23日上午11:47:49 * @version 1.0 */ public class WatchHome implements Home { /** * 能看守家园 */ @Override public void isWatchHome() { System.out.println("我可以守护家园..."); } }
package strategy; /** * * 描述:不能看守家园的接口 * @author chentongwei * @date 2016年5月23日上午11:50:55 * @version 1.0 */ public class NotWatchHome implements Home { /** * 不能看守家园 */ @Override public void isWatchHome() { System.out.println("我不带看家本领..."); } }
package strategy; /** * * 描述:是否能抓老鼠的接口 * @author chentongwei * @date 2016年5月23日上午11:46:07 * @version 1.0 */ public interface Mouse { /** * * 描述:是否能抓老鼠的“算法” * @author chentongwei * @date 2016年5月23日上午11:46:31 * 修改人以及修改时间: * 修改内容: * @version 1.0 */ public void isFetchMouse(); }
package strategy; /** * * 描述:能抓老鼠的接口 * @author chentongwei * @date 2016年5月23日上午11:55:44 * @version 1.0 */ public class FetchMouse implements Mouse { /** * 能抓老鼠的“算法” */ @Override public void isFetchMouse() { System.out.println("我能抓老鼠..."); } }
package strategy; /** * * 描述:看到老鼠假装看不见的接口 * @author chentongwei * @date 2016年5月23日上午11:55:02 * @version 1.0 */ public class NotFetchMouse implements Mouse { /** * 不管抓老鼠的“算法” */ @Override public void isFetchMouse() { System.out.println("不管抓老鼠..."); } }
package strategy; /** * * 描述:可以跟老鼠一起玩耍的接口 * @author chentongwei * @date 2016年5月23日上午11:54:11 * @version 1.0 */ public class PlayWithMouse implements Mouse { /** * 能够跟老鼠一起玩耍的"算法" */ @Override public void isFetchMouse() { System.out.println("跟老鼠一起玩...."); } }
package strategy; /** * * 描述:哈巴狗的实现 * 带有能和老鼠一起玩,不带有看家本领 * @author chentongwei * @date 2016年5月23日下午12:00:06 * @version 1.0 */ public class HaBaDog extends Dog { public HaBaDog() { isWacthHome = new NotWatchHome(); isFetchMouse = new PlayWithMouse(); } public static void main(String[] args) { Dog dog = new HaBaDog(); dog.watchHome(); //不带有看家本领 dog.fetchMouse(); //能和老鼠一起玩 //突然需求变了,变成带有看家本领,并且能抓老鼠 dog.setIsFetchMouse(new FetchMouse()); dog.setIsWacthHome(new WatchHome()); dog.watchHome(); //带有看家本领 dog.fetchMouse(); //能抓老鼠 } }
相关文章推荐
- [POJ3352]Road Construction(缩点,割边,桥,环)
- xtrabackup如何备份mysql数据库
- 线索二叉树
- 196. Delete Duplicate Emails
- Objective-C Runtime
- ReactiveCocoa之RACSignal核心类的使用(三)
- java学习笔记5.23对象和面向对象的思考,继承和多态
- mysql导入导出sql文件
- js循环json字符串
- 通过可视化途径理解你的Spark应用程序
- shell常用操作
- C#多线程之二:ManualResetEvent和AutoResetEvent
- 第1课:通过案例对SparkStreaming 透彻理解三板斧之一
- php 数组随机取值的简单实例
- 【转】第六届蓝桥杯决赛 第二题 完美正方形 (线段树)
- JTA入门:http://blog.chinaunix.net/uid-122937-id-3793220.html
- CentOS修改主机名(hostname)
- JSON详解
- 学生信息管理系统优化
- 认识HTML5的WebSocket