public class Sorter {
public List<Object> sort(List<Object> listTobeSorted) {
List<Object> sortedList = null;
// do sort
return sortedList;
}
}
public class SorterA extends Sorter {
public List<Object> sort(List<Object> listTobeSorted) {
List<Object> sortedList = null;
// do sort using strategy A
return sortedList;
}
}
public class SorterB extends Sorter {
public List<Object> sort(List<Object> listTobeSorted) {
List<Object> sortedList = null;
// do sort using strategy B
return sortedList;
}
}
这些类之间的唯一区别是他们排序的策略不一样。另一种方式是为不同的排序策略定义单独的类,然后将这个类传递给Sorter,在Sorter中只需要根据这个策略来完成排序。
/**
*
*/
package design.patterns.strategy;
import java.util.List;
/**
* @author Brandon B. Lin
*
*/
public class Sorter {
private Comparator strategy;
public Sorter(Comparator strategy) {
this.strategy = strategy;
}
public void setStrategy(Comparator strategy) {
this.strategy = strategy;
}
public List<Object> sort(List<Object> listTobeSorted) {
List<Object> sortedList = null;
// do sort using strategy
return sortedList;
}
}
public interface Comparator {
public int compareTo(Object obaject, Object another);
}
public class ComparatorA implements Comparator {
@Override
public int compareTo(Object obaject, Object another) {
return 0;
}
}
public class ComparatorB implements Comparator {
@Override
public int compareTo(Object obaject, Object another) {
// TODO Auto-generated method stub
return 0;
}
}
现在,我们可以使用Comparator对Sorter进行配置,以实现不同排序算法,事实上,我们甚至可以在程序运行的时候改变排序策略(通过setStrategy方法),这是继承无法做到的。当然,也可以将排序任务全部委托给策略,而在Sorter类中简单地调用策略的排序方法。
策略模式的类图如下:
下面是一个来自StackOverFlow的例子,实现不同的认证策略:
public class AuthenticationHandlerImpl implements AuthenticationHandler {
private Authenticator authenticator;
void authenticate() throws ConnectionException {
authenticator.authenticate();
};
public void setAuthenticator(final Authenticator authenticator){
this.authenticator = authenticator;
}
}
interface Authenticator {
void authenticate();
void setLogin(String login);
void setPassword(String password);
}
class URLAuthenticator implements Authenticator {
public void authenticate() {
//use URLConnection
};
}
class HTTPClientAuthenticator implements Authenticator {
public void authenticate() {
//use HTTPClient
};
}
在Java API中,有许多地方都用到了策略模式。事实上java.util.Arrays提供的数组排序方法就用到了策略模式,其中一个方法声明如下:
public static <T> void sort(T[] a, Comparator<? super T> c)
其中,传递的参数Comparator就是策略。
在Java Swing中,容器类的布局也是通过策略模式来实现的。比如,对于JFrame,可以通过setLayout(LayoutManager manager)来配置布局管理器,如果不这么做,我们可能就要继承JFrame来实现不同的布局,比如FlowJFrame实现流布局,GridJFrame实现网格布局。
在URL中,也用到了策略模式。对于不同协议的URL,如http,ftp,如何读取服务器返回的数据,必须遵循相应的协议。因此,通过策略URLStreamHandler来实现对不同协议的流内容的处理,URLStreamHandler根据协议产生相应的URLConnection,然后使用URLConnection读取数据流中的内容。只不过在这里,策略的Java自动帮我们完成,Java根据URL协议部分自动选择合适的URLStreamHandler来处理流,可以通过几成这个类来实现对自定义协议的支持。
策略模式与命令模式有着很微妙的区别。
策略对象可以采用工厂方法模式来创建,或者通过享元模式(Flyweight)来共享。