摘要:本文深入浅出的讲述了设计模式中的策略模式 , 并给出了简单的示例 , 例子浅显易懂 , 并附带源代码。
策略 模式属于行为模式,其意图是定义一系列算法,把他们一个个封装起来,并且使他们可以互相替换,本末实使得算法可以独立与使用它的客户而变化。在做文字输入软件的时候,有很多的算法可以对一个正文流进行分析,将这些算法硬编码进使用他们的类中是不可取的,其原因如下:
l 需要换行功能的客户程序如果直接包含换行算法代码的话将会变得复杂,这使得客户程序大并且难以维护,尤其当需要支持多种换行算法时为会更严重。
l 不同的是欧需要不同的算法,我们不想支持我们并不使用的换行算法。
l 当换行功能是客户程序的一个难以分割的成分时,增加新的换行算法或改变现有算法将十分困难。
我们可以定义一些类来封装不同的换行算法,从而避免这些问题,一个以这种方法封装的算法成为策略。
例如一个把数组导出为表格的算法,输入一个数组,导出一个表格,当用户想改变导出的表格时,便可以通过改变输出的算法改变输出的结果。如果输出的内容用以网页显示,则输出
<table><tr><td>Jack</td></tr><tr><td>Maya</td></tr><tr><td>Mikes</td></tr><tr><td>Shadow</td></tr></table>
如果输出的结果用以直接的屏幕输出,则可以输出:
+----+----+-----+------+
|Jack|Maya|Mikes|Shadow|
+----+----+-----+------+
相应的UML 如下图所示:
图 1
参与者:
Strategy( 策略 TableExporter):
定义所有支持算法的公共接口。 Context 使用这个接口来调用某 ConcreteStrategy 定义的算法,
ConcreteStrategy( 具体策略,如 HtmlExporter):
以 Strategy 接口实现某具体算法。
Context( 上下文 : client) :
用一个 ConcreteStrategy 对象来配置。
维护一个对 Strategy 对象的引用。
可定义一个接口来让 Strategy 访问它的数据。
协作关系: Strategy 和 Context 互相作用以实现选定的算法。当算法被调用时, Context 可以将该算法所需要的所有数据都传递给该 Strategy, 或者 Context 可以将自身作为一个参数传递给 Strategy 操作,这就让 Strategy 在需要时可以回调 Context 。
Context 将它的客户的请求转发给他的 Strategy 。客户通常创建并传递一个 ConcreteStrategy 对象给该 Context 这样,客户仅与 Context 交互,通常有一系列的 ConcreteStrategy 类可以供客户从中选择。
适用性:
当存在以下情况时使用 Strategy :
l 许多相关的类仅仅是行为有差别,策略提供了一种多个行为中的一个行为来配置一个类的方法。
l 需要使用一个算法的不同变体。
l 算法使用客户不应该知道的数据。
l 一个类定义了多种行为。
例子相关的代码:
TableExporter 代码:
package strategy;
public interface TableExporter{
public String getExported(String[] data);
}
HtmlExporter 代码:
package strategy;
public class HtmlExporter implements TableExporter{
public String getExported(String[] data){
if (data == null ){
return "" ;
}
StringBuffer sb = new StringBuffer();
sb.append( "<table>" );
for ( int i=0;i<data. length ;i++)
sb.append( "<tr><td>" +data[i]+ "</td></tr>" );
sb.append( "</table>" );
return sb.toString();
}
}
LineExporter 代码:
package strategy;
public class LineExporter implements TableExporter{
public String getExported(String[] data){
if (data == null ){
return "" ;
}
StringBuffer top = new StringBuffer( "+" );
StringBuffer mid = new StringBuffer( "|" );
for ( int i =0;i<data. length ;i++){
String str = data[i];
for ( int j=0;j<str.length();j++)
top.append( "-" );
mid.append(str);
top.append( "+" );
mid.append( "|" );
}
top.append( "\n" );
mid.append( "\n" );
return top.toString()+mid.toString()+top.toString();
}
}
Client 代码:
package strategy;
public class Client{
public static void main(String[] args){
String[] data = new String[]{ "Jack" , "Maya" , "Mikes" , "Shadow" };
TableExporter tb;
tb = new HtmlExporter();
System. out .println(tb.getExported(data));
tb = new LineExporter();
System. out .println(tb.getExported(data));
}
}
总结: Strategy 策略使得改变一个算法的实现比较容易,在 Java 中的组件的布局便采用了策略模式,使用靠昨对齐还是居中对齐只是算法的区别。