您的位置:首页 > 其它

策略模式

2016-09-17 14:40 267 查看

1、定义

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

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



策略模式的角色:

抽象策略角色(Strategy):策略类,通常由一个接口或者抽象类实现

具体策略角色(ConcreteStrategy):包装了相关的算法和行为

环境角色(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优点

策略封装比较彻底,也比较安全,用户可以调用策略,但是不知道策略是如何实现的,也不能更改策略

扩展性好,如果解决方法未来可能会增加,可以继续扩展,不用更改原有逻辑代码

摆脱臃肿,避免选择解决方法时使用大量if-else或者switch-case

3.2缺点

会带来类数量上的增加,可以使用工厂方法来解决

客户端必须清楚得知道所有的策略,至少得知道能够调用的策略是什么、有多少

3.3应用场景

针对一个问题有多种解决方法的时候,用来选择具体的哪种方法。

具体的实现方法可以进行自由的切换。

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

面向接口,而不是实现

开放-封闭原则

依赖倒置原则

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实现也应用到了策略模式,这里先放着,因为属于并发的内容

参考资料;

HeadFirst设计模式

http://blog.csdn.net/lovelion/article/details/8765177

http://blog.csdn.net/ydxlt/article/details/50434341

http://blog.csdn.net/u013256816/article/details/51245046

http://blog.csdn.net/wangyang1354/article/details/51647076

http://www.cnblogs.com/kubixuesheng/p/5155644.html

http://www.importnew.com/12853.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: