在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

 

posted on 2015-05-14 17:53  一天做一件小事  阅读(355)  评论(0编辑  收藏  举报