学习是分享和合作式的!
转载请注明出处:http://blog.csdn.net/wdzxl198/article/details/9306775;
文章摘自: http://www.riabook.cn/doc/designpattern/;
考虑您要设计一个更换各种符号的工具类TextCharChange,您是否会采用这样的方式:
1: public void replace() {
2: switch(getChangeType()) {
3: case RN_TYPE:
4: replaceRN();
5: break;
6: case N_TYPE:
7: replaceN();
8: break;
9: case OTHER_TYPE:
10: replaceOTHER():
11: break;
12: ...
13: }
14: }
这么作的缺点是,日后您要增加更换符号的策略时,会有几个地方需要修改:增加TYPE常数、增加TextCharChange中的 replaceXXX()方法、增加 replace()方法中的switch case判断。
像这种策略采用的情况,可以将策略加以封装为一个物件,而不是将策略写死在某个类中,如此一来,策略可以独立于客户端,随时增加变化、增加或减少策略,即使是修改每个策略的内容,也不会对客户端程式造成影响。
来举个最简单的例子,首先要知道Windows与Linux的文字档案换行符号是不同的,Windows是 /r/n ,而Linux是 /n,今天您要设计一个文字编辑器,在适当的时候,您必须要能随时转换这两种符号,如果不采用上面的策略采用流程的话,要如何设计:
- TextStrategy.java
1: public abstract class TextStrategy {
2: protected String text;
3:
4: public TextStrategy(String text) {
5: this.text = text;
6: }
7:
8: public abstract String replace();
9: }
- LinuxStrategy.java
1: public class LinuxStrategy extends TextStrategy {2: public LinuxStrategy(String text) {3: super(text);
4: }
5:
6: public String replace() {7: preOperation();
8: System.out.println(
9: text = text.replaceAll("@r@n", "@n"));10: postOperation();
11:
12: return text;13: }
14:
15: private void preOperation() {16: System.out.println("LinuxStrategy preOperation");17: }
18:
19: private void postOperation() {20: System.out.println("LinuxStrategy postOperation");21: }
22: }
- WindowsStrategy.java
1: public class WindowsStrategy extends TextStrategy {
2: public WindowsStrategy(String text) {
3: super(text);
4: }
5:
6: public String replace() {
7: startOperation();
8: System.out.println(
9: text = text.replaceAll("@n", "@r@n"));
10: endOperation();
11:
12: return text;
13: }
14:
15: private void startOperation() {
16: System.out.println("WindowsStrategy startOperation");
17: }
18:
19: private void endOperation() {
20: System.out.println("WindowsStrategy endOperation");
21: }
22: }
- TextCharChange.java
1: public class TextCharChange {2: public static void replace(TextStrategy strategy) {3: strategy.replace();
4: }
5: }
- Main.java
1: public class Main {2: public static void main(String[] args) {3: String linuxText =
4: "This is a test text!!@n Oh! Line Return!!@n";5: String windowsText =
6: "This is a test text!!@r@n Oh! Line Return@r@n";7:
8: // load file, suppose it's Linux's text file9: // take the WindowsStrategy10: // I want to change it to Windows' text file11: TextCharChange.replace(
12: new WindowsStrategy(linuxText));13:
14: // such-and-such operation.....15: System.out.println();
16:
17: // load file, suppose it's Windows' text file18: // take the LinuxStrategy19: // I want to change it to Linux's text file20: TextCharChange.replace(
21: new LinuxStrategy(windowsText));22: }
23: }
为了明显的秀出结果,我们使用@n来表示 '/n' , @r 表示 '/r' 符号,Main中的流程是个假设的情况,何时采用何种策略是随机的。
在Strategy模式中,使用一个公开的介面replace(),让客户端请求,而在实作replace()时,可以任意的组合演算策略,程式中的 preOperation()、postOperation()就是用以示意演算的组合概念,Strategy模式封装了这些演算过程,使它们易于组合、 修改、替换,上面这个例子的UML 类别结构图如下所示:
Strategy模式的UML类别结构图如下:
从行为上来说,State 模式 与Strategy模式是相近的。
State模式:看当前是什么状态,就采取什么动作。
Strategy模式:看需求(情境)是什么,采用适当的策略。
不过两者虽相似,应用的场合稍有不同,State模式中有一个重点在于设定状态变化,就像 Gof 例子中举的TCP连线;Strategy策略模式则是直接采用适当的策略的感觉,例如Gof中说的,采用适当的演算法来作正文换行。
Edit by Atlas,
Time:09:50