Strategy策略模式

策略模式(Strategy):

它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.)

 

动机:

在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。

如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

策略模式就能使算法与对象本身解耦,能够在需要时透明的更改对象的算法。

通俗点讲,策略模式就是将对象本身的算法进行抽象,从而从对象本身中剥离出来。
比如对某一类对象obj进行比较,我们可能会采取多种比较策略,如果每一种比较策略都在对象obj中写一个实现方法,这个类将会膨胀。
在我们看来,所有的比较归根结底就是比较出两个对象的大小,所以我们可以对这一部分进行抽象,抽成一个comparator比较器,由外部调用处对这个比较器进行注入。这样我们就能灵活的控制到底使用哪一种比较规则了。

 

举例:

比较学生,1:按年龄比较   2:按身高比较

public interface Comparator<T> {
    public int compare(T obj1, T obj2);
}

 

public class Student {
    private String name;
    private int age;
    private double height;
    private Comparator<Student> comparator;
    

    public Comparator<Student> getComparator() {
        return comparator;
    }

    public void setComparator(Comparator<Student> comparator) {
        this.comparator = comparator;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int compare(Student s) {
        return this.comparator.compare(this, s);
    }
}

 

public class StuAgeComparator implements Comparator<Student> {

    @Override
    public int compare(Student s1, Student s2) {
        if(s1.getAge() > s2.getAge()){
            return 1;
        } else if (s1.getAge() == s2.getAge()){
            return 0;
        } else {
            return -1;
        }
    }
    

}

 

public class StuHeightComparator implements Comparator<Student> {

    @Override
    public int compare(Student s1, Student s2) {
        if(s1.getHeight() > s2.getHeight()){
            return 1;
        } else if (s1.getHeight() == s2.getHeight()){
            return 0;
        } else {
            return -1;
        }
    }
    

}

 

客户端调用:

public class Client {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("张三");
        s1.setAge(18);
        s1.setHeight(1.7);
        Student s2 = new Student();
        s2.setName("李四");
        s2.setAge(15);
        s2.setHeight(1.80);
        
        s1.setComparator(new StuAgeComparator());
        System.out.println(s1.compare(s2));
        s1.setComparator(new StuHeightComparator());
        System.out.println(s1.compare(s2));
    }
}

 

 

其实我上面讲的就是JDK中的Comparator这个接口,但是好像还少了点什么,少的就是Comparable这个接口。

这个接口是为通用的排序做准备的。

我们知道Conllections.sort(List<T> args)这个方法是对List中的对象进行排序,不管它里面装的是什么对象。那么我们想对任意的对象进行排序的话,就不能用具体的排序的实现方法,也就是要对排序进行抽象,而排序中重要的一环就是比较两个对象的大小,所以归根结底就是对比较大小进行抽象,使用子类的实现。

所以我们就考虑让所有类型的对象都实现统一的接口,对象比较时都使用这个接口的比较方法,故最终比较时就会使用子类的比较方法的实现来进行大小比较。

 

例:

public interface Comparable<T> {
    public int compareTo(T obj);
}

 

public class Student implements Comparable<Student>{
    private String name;
    private int age;
    private double height;
    private Comparator<Student> comparator = new StuAgeComparator();
    
      // getter/setter方法  

    public int compareTo(Student s) {
        return this.comparator.compare(this, s);
    }
}    

 

客户端调用代码:

public class ClientSort {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("张三");
        s1.setAge(18);
        s1.setHeight(1.7);
        Student s2 = new Student();
        s2.setName("李四");
        s2.setAge(15);
        s2.setHeight(1.80);
        Student s3 = new Student();
        s3.setName("王五");
        s3.setAge(21);
        s3.setHeight(1.65);
        Comparable<Student>[] stus = new Student[3];
        stus[0] = s1;
        stus[1] = s2;
        stus[2] = s3;
        stus = DataSorter.sort(stus);
        for(Comparable<Student> s : stus){
            System.out.println(((Student)s).getName() + ":" + ((Student)s).getAge());
        }
    }
}

 

输出:

李四:15
张三:18
王五:21

 

所以,Comparable这个接口与Strategy策略模式是不相关的,它主要的作用是统一比较接口。

Comparator的实现才是具体的比较策略。

posted on 2014-12-25 18:28  快鸟  阅读(445)  评论(0编辑  收藏  举报