版權聲明:本文出自汪磊的博客,轉載請務必注明出處。
一、策略模式定義
定義:策略模式定義了一系列的算法,並將每一個算法封裝起來,而且使他們之間可以相互替換,策略模式可以在不影響客戶端的情況下發生變化。
好了,定義看看就完了,我知道你很煩看定義。
二、策略模式涉及到的三個角色
環境(Context)角色 持有一個Strategy的引用
抽象策略(Strategy)角色 這是一個抽象角色,通常由一個接口或抽象類實現。此角色給出所有的具體策略類所需的接口。
具體策略(ConcreteStrategy)角色 包裝了具體的算法或行為。
三、策略模式使用舉例
還是趕快看代碼吧,知道你看上面定義都煩死了。
我們寫一個簡單的Demo來對策略模式進行更深的理解,我們模擬游戲中玩家參與一個活動購買金幣,普通玩家沒有折扣,高級玩家9折優惠,VIP玩家7折優惠。
首先我們定義一個接口,這就是抽象策略角色,如下:
1 public interface GameStrategy { 2 3 public void goldCoin(); 4 5 }
很簡單,就是一個接口。
接下來我們編寫具體策略角色類,從需求就能明白,需要有三個具體策略角色類,也就是三個策略對應不同等級玩家。
普通玩家策略類:
1 public class normalStrategy implements GameStrategy { 2 3 @Override 4 public void goldCoin() { 5 // 6 System.out.println("普通玩家沒有折扣"); 7 } 8 }
高級玩家策略類:
public class advancedStrategy implements GameStrategy { @Override public void goldCoin() { // TODO Auto-generated method stub System.out.println("高級會員9折優惠"); } }
VIP玩家策略類:
1 public class vipStrategy implements GameStrategy { 2 3 @Override 4 public void goldCoin() { 5 // 6 System.out.println("VIP會員7折優惠"); 7 } 8 }
都很簡單,就是簡單打印信息。
然后編寫環境角色類,如下:
1 public class Context { 2 //持有一個Strategy的引用 3 private GameStrategy mGameStrategy; 4 5 // 構造函數 6 public Context(GameStrategy strategy) { 7 this.mGameStrategy = strategy; 8 } 9 10 public void setStrategy(GameStrategy strategy) { 11 this.mGameStrategy = strategy; 12 } 13 14 public void goldCoin() { 15 this.mGameStrategy.goldCoin(); 16 } 17 }
最后就是調用了,根據不同情況調用不同策略:
1 public class main { 2 3 public static void main(String[] args) { 4 //普通玩家策略 5 Context context = new Context(new normalStrategy()); 6 context.goldCoin(); 7 //高級玩家策略 8 context.setStrategy(new advancedStrategy()); 9 context.goldCoin(); 10 //高級玩家策略 11 context.setStrategy(new vipStrategy()); 12 context.goldCoin(); 13 } 14 }
不同情況下我們替換為對應策略就可以了。
四、策略模式優缺點
優點
策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行為族。恰當使用繼承可以把公共的代碼移到父類里面,從而避免代碼重復。使用策略模式可以避免使用多重條件(if-else)語句。多重條件語句不易維護,它把采取哪一種算法讓子類實現
缺點
通過上面Demo我們會發現調用者必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類並且由於策略模式把每個具體的策略實現都單獨封裝成為類,如果備選的策略很多的話,那么對象的數目就會很可觀。
好了上面就是策略模式的介紹了,關鍵是自己慢慢理解。接下來我們了解一下狀態模式。
五、狀態模式定義
當一個對象在其內部狀態改變的時候改變其行為。這個對象看上去就像是改變了它的類一樣。又稱狀態對象模式,狀態模式是對象的行為模式。
簡單的理解就是一個類其狀態改變了,那么其功能也相應的改變了。比如水變為冰,狀態改變了,其功能也發生了相應變化。
六、狀態模式角色
● Context(環境類):環境類又稱為上下文類,它是擁有多種狀態的對象。由於環境類的狀態存在多樣性且在不同狀態下對象的行為有所不同,因此將狀態獨立出去形成單獨的狀態類。在環境類中維護一個抽象狀態類State的實例,這個實例定義當前狀態,在具體實現時,它是一個State子類的對象。
● State(抽象狀態類):它用於定義一個接口以封裝與環境類的一個特定狀態相關的行為,在抽象狀態類中聲明了各種不同狀態對應的方法,而在其子類中實現類這些方法,由於不同狀態下對象的行為可能不同,因此在不同子類中方法的實現可能存在不同,相同的方法可以寫在抽象狀態類中。
● ConcreteState(具體狀態類):它是抽象狀態類的子類,每一個子類實現一個與環境類的一個狀態相關的行為,每一個具體狀態類對應環境的一個具體狀態,不同的具體狀態類其行為有所不同。
七、狀態模式使用舉例
接下來我們編寫一個小Demo來進行更深入理解:在辦公系統中,一個文件會有不同狀態:未處理,正在處理,已經處理。我們就簡單模擬一下文件狀態的切換。
首先我們看下抽象狀態類,很簡單就是定義一個接口:
1 public interface State { 2 3 void fileState(); 4 }
接下來看下三個具體狀態類:
未處理狀態類
1 public class NotDealState implements State{ 2 3 @Override 4 public void fileState() { 5 // TODO Auto-generated method stub 6 System.out.println("文件未處理狀態"); 7 } 8 }
正在處理狀態類:
1 public class DealingState implements State{ 2 3 @Override 4 public void fileState() { 5 // TODO Auto-generated method stub 6 System.out.println("文件正在處理狀態"); 7 } 8 }
已經處理狀態類
1 public class HasDealState implements State{ 2 3 @Override 4 public void fileState() { 5 // TODO Auto-generated method stub 6 System.out.println("文件已經處理狀態"); 7 } 8 }
是不是很簡單,同樣也只是打印一些簡單的信息罷了。
然后看下上下文類:
1 public class FileContext { 2 3 //默認情況下未處理狀態 4 private State fileState = new NotDealState(); 5 6 /** 7 * 文件狀態切換為未處理狀態 8 */ 9 public void notDeal(){ 10 11 this.fileState = new NotDealState(); 12 } 13 14 /** 15 * 文件狀態切換為正在處理狀態 16 */ 17 public void Dealing(){ 18 19 this.fileState = new DealingState(); 20 } 21 22 /** 23 * 文件狀態切換為已經處理狀態 24 */ 25 public void HasDeal(){ 26 27 this.fileState = new HasDealState(); 28 } 29 30 /** 31 * 獲取當前文件的狀態 32 */ 33 public void getFileState(){ 34 fileState.fileState(); 35 } 36 }
上下文類主要就是封裝當前文件狀態並且對外提供狀態切換的方法
最后看下怎么使用吧:
1 public class Client { 2 3 public static void main(String[] args) { 4 5 FileContext fileContext = new FileContext(); 6 fileContext.getFileState(); 7 //切換為正在處理狀態 8 fileContext.Dealing(); 9 fileContext.getFileState(); 10 //切換為已經處理狀態 11 fileContext.HasDeal(); 12 fileContext.getFileState(); 13 } 14 }
外部使用調用相應切換狀態方法就可以了,很簡單,沒有什么需要特別說明的。
八、狀態模式與策略模式區別以及聯系
策略模式與狀態模式及其相似,但是二者有其內在的差別,策略模式將具體策略類暴露出去,調用者需要具體明白每個策略的不同之處以便正確使用。而狀態模式狀態的改變是由其內部條件來改變的,與外界無關,二者在思想上有本質區別。
好了,狀態模式與策略模式講解到此為止,二者區別聯系不是幾句話就能說清楚,關鍵是思想上的不同,具體感悟需要在實踐中自己慢慢體會。