策略模式
2016-09-17 14:40
267 查看
1、定义
策略模式定义了算法族,分别封装起来,让他们之间可以相互替代,此模式的变化独立于使用算法的客户上述中的算法即行为、方法,策略模式通俗点说,解决一个问题有多种方法,程序在运行时会自己去选择执行什么方法
策略模式的角色:
抽象策略角色(Strategy):策略类,通常由一个接口或者抽象类实现
具体策略角色(ConcreteStrategy):包装了相关的算法和行为
环境角色(Context):持有一个策略类的引用,最终给客户端调用
2、例子
HeadFirst上面的例子简化版:鸭子能飞,但是每种特定的鸭子飞的行为不一样,这里不一样的是飞这个行为抽象策略类:
public interface FlyBehavior { void fly(); }
具体策略类1:
public class FlyWithWings implements FlyBehavior{ @Override public void fly() { System.out.println("用翅膀飞"); } }
具体策略类2:
public class FlyWithRocket implements FlyBehavior { @Override public void fly() { System.out.println("用火箭飞"); } }
具体策略类3:
public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("不能飞"); } }
抽象环境角色类:
public abstract class Duck { protected FlyBehavior flyBehavior; public void PerformFlyBehavior(){ display(); flyBehavior.fly(); } abstract void display(); }
具体环境角色类1:
public class RedHeadDuck extends Duck { public RedHeadDuck(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } @Override void display() { System.out.print("红头鸭,"); } }
具体环境角色类2:
public class MechanicalDuck extends Duck { public MechanicalDuck(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } @Override void display() { System.out.print("机械鸭,"); } }
具体环境角色类3:
public class SimulatorDuck extends Duck { public SimulatorDuck(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } @Override void display() { System.out.print("模型鸭,"); } }
客户,也就是测试:
public class Test { public static void main(String[] args) { FlyWithWings wings = new FlyWithWings(); FlyWithRocket rocket = new FlyWithRocket(); FlyNoWay noway = new FlyNoWay(); Duck[] ducks = { new RedHeadDuck(wings), new MechanicalDuck(rocket), new SimulatorDuck(noway), }; for (Duck duck : ducks) { duck.PerformFlyBehavior(); } } }
输出:
红头鸭,用翅膀飞 机械鸭,用火箭飞 模型鸭,不能飞
3、优缺点和应用场景
3.1优点
策略封装比较彻底,也比较安全,用户可以调用策略,但是不知道策略是如何实现的,也不能更改策略扩展性好,如果解决方法未来可能会增加,可以继续扩展,不用更改原有逻辑代码
摆脱臃肿,避免选择解决方法时使用大量if-else或者switch-case
3.2缺点
会带来类数量上的增加,可以使用工厂方法来解决客户端必须清楚得知道所有的策略,至少得知道能够调用的策略是什么、有多少
3.3应用场景
针对一个问题有多种解决方法的时候,用来选择具体的哪种方法。具体的实现方法可以进行自由的切换。
4、使用到的面向对象原则
面向接口,而不是实现开放-封闭原则
依赖倒置原则
5、在JDK中的应用
4.1 java.util.Comparator#compare()
强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。以上摘自jdk文档中对Comparator的描述,准确地说是Collections.sort(List list, Comparator
public interface Comparator<T>{ int compare(T o1, T o2); boolean equals(Object obj); …… }
啥意思呢?以Arrays.sort()为例,
static<T> void sort(T[] a, Comparator<? super T> c)根据指定比较器产生的顺序对指定对象数组进行排序。
这里compare方法即是策略,Comparator是抽象策略类,而实现Comparator的类为具体策略类,对于每个不同的对象来说,实现比较器的策略是不一样的,以下为一个简单的例子。
具体策略类:
public class PersonComparator implements Comparator<Person>{ @Override public int compare(Person p1, Person p2) { if(p1.getAge() > p2.getAge()) return 1; else if(p1.getAge() < p2.getAge()) return -1; else return 0; } }
Person类:
public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public int getAge() { return age; } @Override public String toString() { return "name: "+name+", age: "+age; } }
测试类:
import java.util.*; public class ComparatorTest { public static void main(String[] args) { Person[] persons = { new Person("张三", 20), new Person("李四", 50), new Person("王五", 30), }; for (Person person : persons) { System.out.print(person+" "); } //升序排序 Arrays.sort(persons, new PersonComparator()); System.out.println(Arrays.toString(persons)); } }
输出:
[name: 张三, age: 20, name: 李四, age: 50, name: 王五, age: 30] [name: 张三, age: 20, name: 王五, age: 30, name: 李四, age: 50]
这里还有另外一个知识点,ComparableComparator和联系:Cmparable是排序接口,一个类实现类该接口表明“该类支持排序“——可使用Collections.sort(或 Arrays.sort)进行排序,可理解为”内部比较器”;Comparator是比较器接口,一个类本不”支持排序“——无法使用Collections.sort(或 Arrays.sort)进行排序,也就是没有实现Comparable接口,可以额外创建一个比较器类来实现“排序”,可以理解为“外部比较器”
4.2 javax.servlet.http.HttpServlet
HTTP请求实际上只是一个HTTP请求报文,Web容器会自动将这个HTTP请求报文包装成一个HttpServletRequest对象,并且自动调用HttpServlet的 service() 方法来解析这个HTTP请求,service()方法会解析HTTP请求行,而HTTP请求行由method,URI,HTTPVersion三个组成,method就是get或者post,service() 方法根据 method 来决定是执行 doGet 还是 doPost,这一切都是服务器(容器,比如tomcat)自动完成的,HTTP的格式也自动被解析。只要自定义的类继承了HttpServlet,并且在web.xml里面配置了相应的servlet和mapping,服务器就会自动执行以上过程。而自定义servlet必须实现Servlet接口,一般重写doGet()或doPost(),HttpServlet即是抽象策略类,自定以servlet即具体实现类
另外,线程池ThreadPoolExecutor实现和ForkJoin框架的ForkJoinPool实现也应用到了策略模式,这里先放着,因为属于并发的内容
参考资料;
HeadFirst设计模式
http://blog.csdn.net/lovelion/article/details/8765177
http://blog.csdn.net/ydxlt/article/details/50434341
http://blog.csdn.net/u013256816/article/details/51245046
http://blog.csdn.net/wangyang1354/article/details/51647076
http://www.cnblogs.com/kubixuesheng/p/5155644.html
http://www.importnew.com/12853.html
相关文章推荐
- java之流程控制之if语句
- 128.深入 cookie ,session
- Android 简易音乐动态相册(多种动画)
- NumberPicker制作省市选择器/时间选择器
- Ubuntu日记——五行生成一个快捷方式图标
- Maven报错:(请使用 -source 7 或更高版本以启用 diamond 运算符)
- jquery获得option的值和对option进行操作
- Swift 进度条 UIProgressView
- zabbix源码学习之维护状态实现maintenance
- File练习
- 如何在Windows系统上用抓包软件Wireshark截获iPhone等网络通讯数据
- Android下拉刷新代码完全解析,完全解读大神代码,解决两个小bug
- Docker之cgroup篇
- 一篇 介绍 Socket 和 WebSocket 的很好的帖子
- 判断AccessibilityService服务是否已经启动
- 栈和队列常考面试题(二)
- 模拟网页点击事件
- 软件工程第一次作业
- java.猜数字游戏
- Maximum Product of Word Lengths