Design Pattern: Strategy 模式
學習是分享和合作式的!
轉載請注明出處:https://blog.csdn.net/wdzxl198/article/details/9306775;
文章摘自: https://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 file
9: // take the WindowsStrategy
10: // I want to change it to Windows' text file
11: 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 file
18: // take the LinuxStrategy
19: // I want to change it to Linux's text file
20: 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
最後更新:2017-04-03 16:48:33