政策模式與狀态模式在實作上有共同之處,都是把不同的情形抽象為統一的接口來實作,就放在一起進行記錄。2個模式的UML模組化圖基本相似,差別在于狀态模式需要在子類實作與context相關的一個狀态行為。
狀态模式的的思想是,狀态之間的切換,在狀态A執行完畢後自己控制狀态指向狀态B。狀态模式是不停的切換狀态執行。
政策模式的思想上是,考慮多種不同的業務規則将不同的算法封裝起來,便于調用者選擇調用。政策模式隻是條件選擇執行一次。
政策模式
- Strategy: 定義所有支援的算法的公共接口抽象類.
- ConcreteStrategy: 封裝了具體的算法或行為,繼承于Strategy
- Context: 用一個ConcreteStrategy來配置,維護一個對Strategy對象的引用。
狀态模式
- State: 抽象狀态類,定義一個接口以封裝與context的一個狀态相關的行為
- ConcreteState: 具體狀态,每一子類實作一個與Context的一個狀态相關的行為
- Context: 維護一個ConcreteState子類的執行個體,這個執行個體定義目前的狀态。
使用場景:
狀态模式主要解決的是當控制一個對象狀态轉換的條件表達式過于複雜時的情況。把狀态的判斷邏輯轉移到表示不同狀态的一系列類當中,可以把複雜的判斷邏輯簡化。當一個對象的行為取決于它的狀态,并且它必須在運作時刻根據狀态改變它的行為時,就可以考慮使用狀态模式了。
政策模式的Strategy類層次為Context定義了一系列的可供重用的算法或行為。繼承有助于析取出這些算法中的公共功能。在實踐中,我們發現可以用它來封裝幾乎任何類型的規則,隻要在分析過程中聽到需要在不同時間應用不同的業務規則,就可以考慮使用政策模式處理這種變化的可能性。
狀态模式和政策模式的比較
兩個模式的實作類圖雖然一緻,但是實作目的不一樣!
首先知道,政策模式是一個接口的應用案例,一個很重要的設計模式,簡單易用,政策模式一般用于單個算法的替換,用戶端事先必須知道所有的可替換政策,由用戶端去指定環境類需要哪個政策,注意通常都隻有一個最恰當的政策(算法)被選擇。其他政策是同級的,可互相動态的在運作中替換原有政策。
而狀态模式的每個狀态子類中需要包含環境類(Context)中的所有方法的具體實作——條件語句。通過把行為和行為對應的邏輯包裝到狀态類裡,在環境類裡消除大量的邏輯判斷,而不同狀态的切換由繼承(實作)State的狀态子類去實作,當發現修改的目前對象的狀态不是自己這個狀态所對應的參數,則各個狀态子類自己給Context類切換狀态(有職責鍊模式思想)!且用戶端不直接和狀态類互動,用戶端不需要了解狀态!(和政策不一樣),政策模式是直接依賴注入到Context類的參數進行選擇政策,不存在切換狀态的操作,用戶端需要了解政策!
聯系:狀态模式和政策模式都是為具有多種可能情形設計的模式,把不同的處理情形抽象為一個相同的接口(抽象類),符合對開閉原則,且政策模式更具有一般性,在實踐中,可以用政策模式來封裝幾乎任何類型的規則,隻要在分析過程中聽到需要在不同實踐應用不同的業務規則,就可以考慮使用政策模式處理,在這點上政策模式是包含狀态模式的功能的。
小結:狀态模式的使用場景是什麼?
狀态模式主要解決的是(目的or意圖):控制一個對象内部的狀态轉換的條件表達式過于複雜時的情況,且用戶端調用之前不需要了解具體狀态。它把狀态的判斷邏輯轉到表現不同狀态的一系列類當中,可以把複雜的判斷邏輯簡化。維持開閉原則,友善維護
,還有重要一點下面會總結,狀态模式是讓各個狀态對象自己知道其下一個處理的對象是誰!即在狀态子類編譯時在代碼上就設定好了!
狀态模式的優缺點都是什麼?
優點,前面說了很多了……
- 狀态模式使得代碼中複雜而庸長的邏輯判斷語句問題得到了解決,而且狀态角色将具體的狀态和他對應的行為及其邏輯判斷封裝了起來,這使得增加一種新的狀态顯得十分簡單。
- 把容易出錯的if-else語句在環境類 or 用戶端中消除,友善維護。
- 每一個狀态類都符合“開閉”原則——對狀态的修改關閉,對用戶端的擴充開放,可以随時增加新的Person的狀态,或者删除。
- State類在隻有行為需要抽象時,就用接口,有其他共同功能可以用抽象類,這點和其他一些(政策)模式類似。
缺點:
使用狀态模式時,每個狀态對應一個具體的狀态類,使結構分散,類的數量變得很多!使得程式結構變得稍顯複雜,閱讀代碼時相對之前比較困難,不過對于優秀的研發人員來說,應該是微不足道的。因為想要擷取彈性!就必須付出代價!除非我們的程式是一次性的!用完就丢掉……如果不是,那麼假設有一個系統,某個功能需要很多狀态,如果不使用狀态模式優化,那麼在環境類(用戶端類)裡會有大量的整塊整塊的條件判斷語句!
Strategy模式有下面的一些優點:
1) 相關算法系列 Strategy類層次為Context定義了一系列的可供重用的算法或行為。 繼承有助于析取出這些算法中的公共功能。
2) 提供了可以替換繼承關系的辦法: 繼承提供了另一種支援多種算法或行為的方法。你可以直接生成一個Context類的子類,進而給它以不同的行為。但這會将行為硬行編制到 Context中,而将算法的實作與Context的實作混合起來,進而使Context難以了解、難以維護和難以擴充,而且還不能動态地改變算法。最後你得到一堆相關的類 , 它們之間的唯一差别是它們所使用的算法或行為。 将算法封裝在獨立的Strategy類中使得你可以獨立于其Context改變它,使它易于切換、易于了解、易于擴充。
3) 消除了一些if else條件語句 :Strategy模式提供了用條件語句選擇所需的行為以外的另一種選擇。當不同的行為堆砌在一個類中時 ,很難避免使用條件語句來選擇合适的行為。将行為封裝在一個個獨立的Strategy類中消除了這些條件語句。含有許多條件語句的代碼通常意味着需要使用Strategy模式。
4) 實作的選擇 Strategy模式可以提供相同行為的不同實作。客戶可以根據不同時間 /空間權衡取舍要求從不同政策中進行選擇。
Strategy模式缺點:
1)用戶端必須知道所有的政策類,并自行決定使用哪一個政策類: 本模式有一個潛在的缺點,就是一個客戶要選擇一個合适的Strategy就必須知道這些Strategy到底有何不同。此時可能不得不向客戶暴露具體的實作問題。是以僅當這些不同行為變體與客戶相關的行為時 , 才需要使用Strategy模式。
2 ) Strategy和Context之間的通信開銷 :無論各個ConcreteStrategy實作的算法是簡單還是複雜, 它們都共享Strategy定義的接口。是以很可能某些 ConcreteStrategy不會都用到所有通過這個接口傳遞給它們的資訊;簡單的 ConcreteStrategy可能不使用其中的任何資訊!這就意味着有時Context會建立和初始化一些永遠不會用到的參數。如果存在這樣問題 , 那麼将需要在Strategy和Context之間更進行緊密的耦合。
3 )政策模式将造成産生很多政策類:可以通過使用享元模式在一定程度上減少對象的數量。 增加了對象的數目 Strategy增加了一個應用中的對象的數目。有時你可以将 Strategy實作為可供各Context共享的無狀态的對象來減少這一開銷。任何其餘的狀态都由 Context維護。Context在每一次對Strategy對象的請求中都将這個狀态傳遞過去。共享的 Strategy不應在各次調用之間維護狀态。
1 public interface IStrategy
2 {
3 double CountMoney(double money);
4 }
5
6
7 public class discountA:IStrategy
8 {
9 public double CountMoney(double money)
10 {
11 return money * 0.8;
12 // throw new NotImplementedException();
13 }
14 }
15
16 /// <summary>
17 /// 打折活動B
18 /// </summary>
19 public class discountB:IStrategy
20 {
21
22 /// <summary>
23 /// 滿100-20
24 /// </summary>
25 /// <param name="money"></param>
26 /// <returns></returns>
27 public double CountMoney(double money)
28 {
29 return money - ((int)(money / 100) * 20);
30 //throw new NotImplementedException();
31 }
32 }
33
34 public class Strategy
35 {
36 IStrategy iStrategy;
37 public Strategy(IStrategy strategy)
38 {
39 iStrategy = strategy;
40 }
41 public double CountMoney(double money)
42 {
43 return iStrategy.CountMoney(money);
44 }
45 }
46
47 public class MainStrategys
48 {
49 public MainStrategys()
50 {
51 Strategy strategt;
52 //執行A打折政策
53 discountA da = new discountA();
54 strategt = new Strategy(da);
55 Console.WriteLine("A打折政策--"+strategt.CountMoney(111));
56
57 //執行B打折政策
58 discountB db = new discountB();
59 strategt = new Strategy(db);
60 Console.WriteLine("B打折政策--" + strategt.CountMoney(111));
61
62 Console.ReadKey();
63 }
64 }
政策模式
1 public interface IState
2 {
3 void Submit(FileSub file);
4 }
5
6 public class BeginState :IState
7 {
8
9 public void Submit(FileSub file)
10 {
11 Console.WriteLine("begin-------");
12 file.SetState(new WorkingState());
13 }
14 }
15
16 public class WorkingState:IState
17 {
18 public void Submit(FileSub file)
19 {
20 Console.WriteLine("working-------------");
21 file.SetState(new EndState());
22 //throw new NotImplementedException();
23 }
24 }
25
26
27 public class EndState:IState
28 {
29 public void Submit(FileSub file)
30 {
31 Console.WriteLine("end------------");
32 file.SetState(new BeginState());
33 //throw new NotImplementedException();
34 }
35 }
36
37 public class FileSub
38 {
39 private IState istate;
40 public FileSub()
41 {
42 istate = new BeginState();
43 }
44 public void SetState(IState state)
45 {
46 istate = state;
47 }
48 public void Submit()
49 {
50 istate.Submit(this);
51 }
52 }
53
54 public class Main
55 {
56 public Main()
57 {
58 FileSub file = new FileSub();
59 file.SetState(new BeginState());
60 file.Submit();
61 file.Submit();
62 file.Submit();
63 Console.ReadKey();
64 }
65 }
狀态模式