在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策略模式的更多相关文章

  1. 设计模式------STRATEGY(策略模式)

    http://blog.csdn.net/wuzhekai1985/article/details/6665197.仅供参考. 策略模式:实现替换功能,如cache替换算法:当发生Cache缺失时,C ...

  2. JAVA设计模式之策略模式 - Strategy

    在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式. 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 ...

  3. PHP设计模式-策略模式 转

    策略模式(Strategy Pattern) 策略模式是对象的行为模式,用意是对一组算法的封装.动态的选择需要的算法并使用. 策略模式指的是程序中涉及决策控制的一种模式.策略模式功能非常强大,因为这个 ...

  4. Provider Pattern提供者模式和策略模式

    http://www.codeproject.com/Articles/18222/Provider-Pattern Introduction Provider pattern is one of t ...

  5. 策略模式-Strategy(Java实现)

    策略模式-Strategy 在策略模式中,一个类(策略使用者)可以更改自己的执行策略. 比如以排序算法为例子, 多种排序算法都归属于排序算法, 但是实现的算法细节不同, 使用者可以很轻松地替换策略, ...

  6. 十、Strategy 策略模式

    需求:使用不同的算法解决相同的问题 设计原理: 代码清单: 接口 Strategy public interface Strategy { public abstract Hand nextHand( ...

  7. 策略模式(Strategy)简介

    一.策略模式(Strategy)简介 策略模式是行为模式. 行为模式:规定了各个对象应该具备的职责以及对象间的通信模式,它很好的规范了对象间调用和数据传递方式 策略模式适合于算法经常变化的情况 算法的 ...

  8. 设计模式复习小结一(Strategy Pattern/Observer Pattern/Decorator Patter/Factory Pattern)

    目录: 前言 1. Stratrgy Pattern 2. Observer Pattern 3. Decorator Pattern 4. Factory Pattern 4.1 FactoryPa ...

  9. Java设计模式—策略模式

    1.策略模式(Strategy Pattern)是一种比较简单的模式,也叫做政策模式(PolicyPattern). 定义如下:     Define a family of algorithms,e ...

随机推荐

  1. Linux之RHEL6的开机流程分析

    开机——很多人觉得很简单的事情,只要按下电源开关,然后系统就会自然启动,没有什么需要学习的.其实不然,如果系统没有什么问题,可以正常登陆的时候,当然开机很简单.但更多的时候,我们需要知道当机子不能正常 ...

  2. Discuz!模板解析语法

    <!--{eval echo autostart("); }--> PHP中使用template()函数显示已存在模板 在Discuz!程序执行中可以通过 include tem ...

  3. 对线程等待函数pthread_join二级指针参数分析

    分析之前先搞明白,这个二级指针其实在函数内部是承接了上个线程的返回值. 看man手册,发现返回值是个普通指针.人家用二级指针来承接,可能准备干大事.这个可以自己搜索一下.原因嘛,二级指针是保存了这个地 ...

  4. Eclipse通过DDMS打开真机/data/data/目录

    一般真机调试时DDMS里面的File Explorer是不能打开/data 目录的,不过也很容易解决. 1.首先手机要root.这个很简单,网上一大堆资料和软件. 2.仅仅root之后还不行,下载一个 ...

  5. Using Call_Form in Oracle D2k

    Using Call_Form in Oracle D2k CALL_FORM examples/* Example 1:** Call a form in query-only mode.*/BEG ...

  6. mysql 存储过程和事件调度

    存储过程(procedure): 建立一个存储过程需要知道的基础知识 1.确定输入/输出的参数和类型: IN tname varchar(20) 其中 IN 表示输入参数,tname  是参数名 va ...

  7. 微信小程序-数据缓存

    每个微信小程序都可以有自己的本地缓存,可以通过 wx.setStorage(wx.setStorageSync).wx.getStorage(wx.getStorageSync).wx.clearSt ...

  8. SQL-Server使用点滴(二)

    二,对象的建立和使用 1,了解MSSql的[系统表] 对于SQL-Server中的所有对象,包括数据库,数据表,记录,字段,触发器,索引,数据类型等元素,均有对应的系统表记性记录.系统表是禁止直接删改 ...

  9. IE11 iframe alternative

    <OBJECT classid=clsid:8856F961-340A-11D0-A96B-00C04FD705A2> <PARAM NAME=Location VALUE=http ...

  10. jq

    1: http://jquery.cuishifeng.cn/index.html jquery 学习查询首页<br> 2: http://m.oschina.net/blog/75741 ...