策略模式

1、定义

策略模式定义了算法族,分别封装起来,让他们之间可以相互替代,此模式的变化独立于使用算法的客户

上述中的算法即行为、方法,策略模式通俗点说,解决一个问题有多种方法,程序在运行时会自己去选择执行什么方法

**插入StrategyUML**

策略模式的角色:

  1. 抽象策略角色(Strategy):策略类,通常由一个接口或者抽象类实现
  2. 具体策略角色(ConcreteStrategy):包装了相关的算法和行为
  3. 环境角色(Context):持有一个策略类的引用,最终给客户端调用

2、例子

HeadFirst上面的例子简化版:鸭子能飞,但是每种特定的鸭子飞的行为不一样,这里不一样的是飞这个行为

抽象策略类

public interface FlyBehavior {
    void fly();
}

具体策略类1

public class FlyWithWings implements FlyBehavior{

    @Override
    public void fly() {
        System.out.println("用翅膀飞");
    }

}

具体策略类2

public class FlyWithRocket implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("用火箭飞");
    }

}

具体策略类3

public class FlyNoWay implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("不能飞");
    }

}

抽象环境角色类

public abstract class Duck {
    protected FlyBehavior flyBehavior;

    public void PerformFlyBehavior(){
        display();
        flyBehavior.fly();
    }

    abstract void display();
}

具体环境角色类1

public class RedHeadDuck extends Duck {

    public RedHeadDuck(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    @Override
    void display() {
        System.out.print("红头鸭,");
    }

}

具体环境角色类2

public class MechanicalDuck extends Duck {

    public MechanicalDuck(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    @Override
    void display() {
        System.out.print("机械鸭,");
    }

}

具体环境角色类3

public class SimulatorDuck extends Duck {

    public SimulatorDuck(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    @Override
    void display() {
        System.out.print("模型鸭,");
    }

}

客户,也就是测试

public class Test {

    public static void main(String[] args) {
        FlyWithWings wings = new FlyWithWings();
        FlyWithRocket rocket = new FlyWithRocket();
        FlyNoWay noway = new FlyNoWay();        
        Duck[] ducks = {
                new RedHeadDuck(wings),
                new MechanicalDuck(rocket),
                new SimulatorDuck(noway),
        };
        for (Duck duck : ducks) {
            duck.PerformFlyBehavior();
        }
    }

}

输出:

红头鸭,用翅膀飞
机械鸭,用火箭飞
模型鸭,不能飞

3、优缺点和应用场景

3.1优点

  1. 策略封装比较彻底,也比较安全,用户可以调用策略,但是不知道策略是如何实现的,也不能更改策略
  2. 扩展性好,如果解决方法未来可能会增加,可以继续扩展,不用更改原有逻辑代码
  3. 摆脱臃肿,避免选择解决方法时使用大量if-else或者switch-case

3.2缺点

  1. 会带来类数量上的增加,可以使用工厂方法来解决
  2. 客户端必须清楚得知道所有的策略,至少得知道能够调用的策略是什么、有多少

3.3应用场景

  1. 针对一个问题有多种解决方法的时候,用来选择具体的哪种方法。
  2. 具体的实现方法可以进行自由的切换。

4、使用到的面向对象原则

  1. 面向接口,而不是实现
  2. 开放-封闭原则
  3. 依赖倒置原则

5、在JDK中的应用

4.1 java.util.Comparator#compare()

强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。

以上摘自jdk文档中对Comparator的描述,准确地说是Collections.sort(List list, Comparator

     public interface Comparator<T>{

        int compare(T o1, T o2);

        boolean equals(Object obj);

        ……
     }

啥意思呢?以Arrays.sort()为例, static<T> void sort(T[] a, Comparator<? super T> c)根据指定比较器产生的顺序对指定对象数组进行排序。

这里compare方法即是策略,Comparator是抽象策略类,而实现Comparator的类为具体策略类,对于每个不同的对象来说,实现比较器的策略是不一样的,以下为一个简单的例子。

具体策略类:

public class PersonComparator implements Comparator<Person>{

    @Override
    public int compare(Person p1, Person p2) {
        if(p1.getAge() > p2.getAge())
            return 1;
        else if(p1.getAge() < p2.getAge())
            return -1;
        else
            return 0;
    }

}

Person类:

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "name: "+name+", age: "+age;
    }
}

测试类:

import java.util.*;

public class ComparatorTest {

    public static void main(String[] args) {
        Person[] persons = {
                new Person("张三", 20),
                new Person("李四", 50),
                new Person("王五", 30),
        };
        for (Person person : persons) {
            System.out.print(person+" ");
        }
        //升序排序
        Arrays.sort(persons, new PersonComparator());
        System.out.println(Arrays.toString(persons));
    }
}

输出:

[name: 张三, age: 20, name: 李四, age: 50, name: 王五, age: 30]
[name: 张三, age: 20, name: 王五, age: 30, name: 李四, age: 50]

这里还有另外一个知识点,ComparableComparator和联系:Cmparable是排序接口,一个类实现类该接口表明“该类支持排序“——可使用Collections.sort(或 Arrays.sort)进行排序,可理解为”内部比较器”;Comparator是比较器接口,一个类本不”支持排序“——无法使用Collections.sort(或 Arrays.sort)进行排序,也就是没有实现Comparable接口,可以额外创建一个比较器类来实现“排序”,可以理解为“外部比较器”

4.2 javax.servlet.http.HttpServlet

HTTP请求实际上只是一个HTTP请求报文,Web容器会自动将这个HTTP请求报文包装成一个HttpServletRequest对象,并且自动调用HttpServlet的 service() 方法来解析这个HTTP请求,service()方法会解析HTTP请求行,而HTTP请求行由method,URI,HTTPVersion三个组成,method就是get或者post,service() 方法根据 method 来决定是执行 doGet 还是 doPost,这一切都是服务器(容器,比如tomcat)自动完成的,HTTP的格式也自动被解析。只要自定义的类继承了HttpServlet,并且在web.xml里面配置了相应的servlet和mapping,服务器就会自动执行以上过程。

而自定义servlet必须实现Servlet接口,一般重写doGet()或doPost(),HttpServlet即是抽象策略类,自定以servlet即具体实现类

另外,线程池ThreadPoolExecutor实现和ForkJoin框架的ForkJoinPool实现也应用到了策略模式,这里先放着,因为属于并发的内容

参考资料;

  1. HeadFirst设计模式
  2. http://blog.csdn.net/lovelion/article/details/8765177
  3. http://blog.csdn.net/ydxlt/article/details/50434341
  4. http://blog.csdn.net/u013256816/article/details/51245046
  5. http://blog.csdn.net/wangyang1354/article/details/51647076
  6. http://www.cnblogs.com/kubixuesheng/p/5155644.html
  7. http://www.importnew.com/12853.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值