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 }; }
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)来共享。