Strategy pattern策略模式
在Java的集合框架中,经常需要通过构造方法传入一个比较器Comparator,或者创建比较器传入Collections的静态方法中作为方法参数,进行比较排序等,使用的是策略模式。
一、策略模式的定义
定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
二、策略模式体现了两个非常基本的面向对象设计原则:
封装变化的概念,找出应用中可能需要变化之处,把它独立出来,不要把那些不需要变化的代码混在一起,系统会变得更有弹性。
编程中使用接口,而不是对接口的实现。
三、策略模式的角色组成

抽象策略角色:策略类,通常由一个接口或者抽象类实现
具体策略角色:包装了相关的算法和行为
环境角色:持有一个策略类的引用,最终给客户端调用的
四、编写策略模式的一般步骤:
1. 对策略对象定义一个公共接口
2. 编写具体策略类,该类实现了上面的接口
3. 在使用策略对象的类(即:环境角色)中保存一个对策略对象的引用
4. 在使用策略对象的类中,实现对策略对象的set和get方法(注入)或者使用构造方法完成赋值
5. 客户端进行调用
五、示例代码
/**
* 策略类
*
*/
public abstract class Strategy { public abstract void algorithmln() ;
}
/**
*具体策略类
*/
public class ConcreateStrategyA extends Strategy{ @Override
public void algorithmln() {
System.out.println("A");
}
} /**
*具体策略类
*/
public class ConcreateStrategyB extends Strategy{ @Override
public void algorithmln() {
System.out.println("B");
}
} /**
*具体策略类
*/
public class ConcreateStrategyC extends Strategy{ @Override
public void algorithmln() {
System.out.println("C");
}
}
/**
*环境角色
*/
public class Context { //定义一个对策略对象的引用
private Strategy strategy; public Context(Strategy strategy) {
this.strategy=strategy;
} public void contextStrategy() {
strategy.algorithmln();
}
}
测试代码
public class TestStrategy {
public static void main(String[] args) {
//测试
Context contextA=new Context(new ConcreateStrategyA());
contextA.contextStrategy();
Context contextB=new Context(new ConcreateStrategyB());
contextB.contextStrategy();
Context contextC=new Context(new ConcreateStrategyC());
contextC.contextStrategy();
}
}
输出结果
A
B
C
策略模式在Java中处处可以体现,TreeSet和TreeMap中均存在这样的构造方法:TreeSet(Comparator<? super E> comparator)和TreeMap(Comparator<? superK> comparator),对它的描述为:构造一个空的TreeSet,它根据指定比较器进行排序。这里的指定比较器就是我们根据需要自己写的“算法”,这就是策略模式最基本的使用方式。
Java实现代码
要求:有这样一个类Class Person,包含id、name、age属性,有若干了Person对象存储在List中,要求对他们进行排序,分别按照名字、年龄、id进行排序(要有正序与倒序两种方式)。如果年龄或者姓名重复,则按照id的正序进行排列。要求使用策略模式进行。
思路分析:可以将若干Person类存放在ArrayList中,然后利用Collections中的 sort(List<T> list,Comparator<? super T> c)方法根据指定比较器产生的顺序对指定列表进行排序,我们要实现具体的比较规则,由于Comparator是一个接口,正好可以作为步骤一中的抽象策略角色。
1. 对策略对象定义一个公共接口
省了一步,直接用接口Comparator即可
2. 编写具体策略类,该类实现了上面的接口
按name进行排序的具体策略类SortByName,其它SortById和SortByAge与之类似:
package com.StrategyJob;
import java.util.Comparator;
public class SortByName implements Comparator {
private int sortType = 0 ; // 定义标记位,默认是采用升序排列
@Override
public int compare(Object arg0, Object arg1) {
Person p0 = (Person)arg0 ;
Person p1 = (Person)arg1 ;
String name0 = p0.name ;
String name1 = p1.name ;
int id0 = p0.id ;
int id1 = p1.id ;
if(name0.endsWith(name1)){
return id0 - id1 ;
}
if(this.sortType != 0 ){
return name1.compareTo(name0);
}else{
return name0.compareTo(name1);
}
}
// 设置排序类型
public void setSortType(int sign)
{
this.sortType = sign ;
}
}
3. 在使用策略对象的类(即:环境角色)中保存一个对策略对象的引用 ; 在使用策略对象的类中,实现对策略对象的set和get方法(注入)或者使用构造方法完成赋值
这里3和4的步骤是在一起
package com.StrategyJob;
import java.util.Comparator;
public class Environment {
private Comparator comparator ; // 私有的抽象策略角色的引用
public Environment(Comparator comp)
{
this.comparator = comp ;
}
public void setComparator(Comparator comp){
this.comparator = comp ;
}
public Comparator getComparator(){
return this.comparator;
}
客户端进行调用
public static void main(String[] args){
// 按姓名name进行排序
SortByName sortbyname = new SortByName() ;
Environment environment = new Environment(sortbyname);
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
Person p4 = new Person();
ArrayList list = new ArrayList();
p1.setName("zhangsan");
p1.setId(1);
p1.setAge(20);
p2.setName("lisi");
p2.setId(5);
p2.setAge(25);
p3.setName("wangwu");
p3.setId(16);
p3.setAge(5);
p4.setName("zhangsan");
p4.setId(6);
p4.setAge(5);
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
System.out.println("--------------------- 按照name升序排列 -----------------------");
// 按照name进行排序
Collections.sort(list, environment.getComparator());
for(Iterator iter = list.iterator() ; iter.hasNext() ; ){
Person p = (Person)iter.next();
String name = p.name ;
int id = p.id ;
System.out.println(name + " "+ id);
}
sortbyname.setSortType(1);
System.out.println("--------------------- 按照name降序排列start -----------------------");
// 按照name进行排序
Collections.sort(list, environment.getComparator());
for(Iterator iter = list.iterator() ; iter.hasNext() ; ){
Person p = (Person)iter.next();
String name = p.name ;
int id = p.id ;
System.out.println(name + " "+ id);
}
System.out.println("---------------------- 按照id升序排列 ----------------------");
SortById sortbyid = new SortById();
environment.setComparator(sortbyid);
Collections.sort(list, environment.getComparator());
for(Iterator iter = list.iterator() ; iter.hasNext() ; ){
Person p = (Person)iter.next();
int id = p.id ;
System.out.println(id + "");
}
System.out.println("---------------------- 按照id降序排列 ----------------------");
sortbyid.setSortType(1);
Collections.sort(list, environment.getComparator());
for(Iterator iter = list.iterator() ; iter.hasNext() ; ){
Person p = (Person)iter.next();
int id = p.id ;
System.out.println(id + "");
}
System.out.println("---------------------- 按照age升序排列 ----------------------");
SortByAge sortbyage = new SortByAge();
environment.setComparator(sortbyage);
Collections.sort(list, environment.getComparator());
for(Iterator iter = list.iterator() ; iter.hasNext() ; ){
Person p = (Person)iter.next();
int age = p.age ;
System.out.println(age + " " + p.id);
}
System.out.println("---------------------- 按照age降序排列 ----------------------");
sortbyage.setSortType(1);
Collections.sort(list, environment.getComparator());
for(Iterator iter = list.iterator() ; iter.hasNext() ; ){
Person p = (Person)iter.next();
int age = p.age ;
System.out.println(age + " " + p.id);
}
}
运行结果

应用场景和优缺点
对于Strategy模式来说,主要有这些应用场景:
1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现
3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
对于Strategy模式来说,主要有如下优点:
1、 提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
对于Strategy模式来说,主要有如下缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
参考资料
《Head First Design Patterns》
http://blog.csdn.net/houqd2012/article/details/12585093?utm_source=tuicool
Strategy pattern策略模式的更多相关文章
- 设计模式------STRATEGY(策略模式)
http://blog.csdn.net/wuzhekai1985/article/details/6665197.仅供参考. 策略模式:实现替换功能,如cache替换算法:当发生Cache缺失时,C ...
- JAVA设计模式之策略模式 - Strategy
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式. 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 ...
- PHP设计模式-策略模式 转
策略模式(Strategy Pattern) 策略模式是对象的行为模式,用意是对一组算法的封装.动态的选择需要的算法并使用. 策略模式指的是程序中涉及决策控制的一种模式.策略模式功能非常强大,因为这个 ...
- Provider Pattern提供者模式和策略模式
http://www.codeproject.com/Articles/18222/Provider-Pattern Introduction Provider pattern is one of t ...
- 策略模式-Strategy(Java实现)
策略模式-Strategy 在策略模式中,一个类(策略使用者)可以更改自己的执行策略. 比如以排序算法为例子, 多种排序算法都归属于排序算法, 但是实现的算法细节不同, 使用者可以很轻松地替换策略, ...
- 十、Strategy 策略模式
需求:使用不同的算法解决相同的问题 设计原理: 代码清单: 接口 Strategy public interface Strategy { public abstract Hand nextHand( ...
- 策略模式(Strategy)简介
一.策略模式(Strategy)简介 策略模式是行为模式. 行为模式:规定了各个对象应该具备的职责以及对象间的通信模式,它很好的规范了对象间调用和数据传递方式 策略模式适合于算法经常变化的情况 算法的 ...
- 设计模式复习小结一(Strategy Pattern/Observer Pattern/Decorator Patter/Factory Pattern)
目录: 前言 1. Stratrgy Pattern 2. Observer Pattern 3. Decorator Pattern 4. Factory Pattern 4.1 FactoryPa ...
- Java设计模式—策略模式
1.策略模式(Strategy Pattern)是一种比较简单的模式,也叫做政策模式(PolicyPattern). 定义如下: Define a family of algorithms,e ...
随机推荐
- javascript 变量提前
1. 未声明变量时,结果是我们预期的结果,报错这个变量没有定义. (function() { // 报错:variable is not defined console.log(variable); ...
- TTradmin v1.1 - 免端口映射穿透任何内网、基于radmin核心的即时远程协助
TTradmin 是一款免端口映射可直接穿透任何内网,基于radmin核心的即时远程协助软件.在使用的时候只需要保证“协助端”和“被协助端”使用同一个验证码即可实现安全便捷的远程控制,不需要进 ...
- 工作中积累整理-CSS样式表(一)
[layout] clear:该属性的值指出了不允许有浮动对象的边. 默认值:none none: 允许两边都可以有浮动对象 both: 不允许有浮动对象 left: 不允许左边有浮动对象 right ...
- 参考:鼠标点击事件(Selenium)
1.鼠标右键点击操作:Actions action = new Actions(driver) ;action.contextClick(driver.findElement(By.xpath(xpa ...
- Python3基础 访问列表指定索引值的元素
镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...
- tomcat启动超时问题
当启动tomcat时候出现 Server Tomcat v6.0 Server at localhost was unable to start within 45 seconds. If the s ...
- 如何修改Hadoop的默认日志级别,还真是麻烦
鄙人使用的Hadoop版本为2.6.4.Hadoop的默认日志级别为INFO,对于百台以上的集群,如果文件操作频繁的话,NameNode会狂打日志,对性能会有一定的影响. 我们可以通过http://& ...
- 通过js给android控件WebView设padding
项目中有个界面是用来显示一个网页的,很简单,放个WebView就ok了,可是返回按钮放在哪 ,ui的设计是在底部显示一个半透明的条,左边有一个返回按钮.这个条显示在内容上面.我有一个担心,就是要是最下 ...
- IE11 HTML Help ActiveX
<!--by: @qab--> <OBJECT id=HHCTRL type="application/x-oleobject" classid="cl ...
- IOS7 edgesForExtendedLayout
在iOS 7中,苹果引入了一个新的属性,叫做[UIViewController setEdgesForExtendedLayout:],它的默认值为UIRectEdgeAll.当你的容器是naviga ...