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 ...
随机推荐
- 头一次试验angularjs
<!DOCTYPE html> <head> <meta charset="utf-8" /> <title>angular< ...
- javascript对象创建方式
工厂模式 在ECMAscript中无法创建类,所以开发人员就发明了一种函数,用函数来封装,以特定接口创建对象的细节,如下面的例子所示: function createPerson(name,age,j ...
- VirtualBox piix4_smbus Error
VirtualBox piix4_smbus Error VirtualBox 3.2.10 gives me the following error message when booting U ...
- Nginx模块之———— RTMP 模块的在线统计功能 stat 数据流数据的获取(不同节点则获取的方式不同)
一.目前只有一个Live节点存在 单节点获取方式如下: public function getStreamByIp($outerIP, $streamName) { //查询录像模块的IP地址外网,根 ...
- html中css、div命名规范
html中css.div命名规范 1.类class的命名规范示例 头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column ...
- 【积累】validate验证框架的使用
validate验证框架的使用:用验证框架可以很方便的验证前端页面输入的内容可以自定义验证方法 内容:0:环境搭建 1:基础用法 2:自定义用法 0:基本环境的搭建 0.1:下载js文件 0.2:引入 ...
- JSONObject,JSONArray,Map,String之间转换
http://blog.csdn.net/superit401/article/details/51727739 1.String转JSONObject String jsonMessage = &q ...
- apache2.4以上版本配置虚拟主机
一 将 主配置文件 httpd.conf中 #Include conf/extra/httpd-vhosts.conf 前面的# 去掉 二 进入conf/extra 修改 /conf/extra/ ...
- cfDNA(circulating cell free DNA)全基因组测序
参考资料: [cfDNA专题]cell-free DNA在非肿瘤疾病中的临床价值(好) ctDNA, cfDNA和CTCs有什么区别吗? cfDNA你懂多少? 新发现 | 基因是否表达,做个cfDNA ...
- 20个人艰不拆的事实:知道真相的我眼泪掉下来 T.T
20个人艰不拆的事实:知道真相的我眼泪掉下来 T.T 原文链接http://www.u148.net/article/113612.html 来源:ruoning WuMo是丹麦画家Mikael Wu ...