策略模式用于演算法的自由切換和擴展,實作了演算法定義和演算法分離的使用
模式動機
要完成一項任務,可以有多種不同的方式,例如人們外出旅游時可以選擇多種不同的出行方式,如自行車、坐汽車、坐高鐵或乘飛機等,每一種方式稱為一個策略,我們可以根據環境或者條件的不同選擇不同的策略來完成該任務,
在實際的軟體開發中,一項功能也有很多演算法可以實作,如果我們直接把多種演算法集中在一個類,或者說使用條件判斷陳述句來進行選擇,無疑會增加代碼復雜性,不利于維護,
為了解決這些問題,可以定義一些獨立的類來封裝不同的演算法,每一類封裝一個具體的演算法,將每一個封裝演算法的類稱之為策略(Strategy),為了保證策略的一致性,一般會用一個抽象的策略類來做演算法的定義,每種具體演算法對應于一個具體策略類,
模式定義
策略模式(Strategy Pattern)定義一系列演算法,將每個演算法封裝起來,并讓它們可以相互替換,策略模式讓演算法獨立于使用它的客戶而變化,也稱政策模式(Policy),策略模式是一種物件行為模式,
Define a famliy of algorithms, encapsulate each one,and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
模式分析
說到策略模式就不得不提一下狀態模式了,一個是對狀態的封裝,另一個則是對演算法的封裝,因此實作方式上兩者有許多共同點,理解起來并不復雜
點這里了解狀態模式
策略模式是對演算法的封裝,把演算法的責任和演算法本身分割開來,委托給不同物件管理,策略模式通常把一系列演算法封裝到一系列的策略類里面,作為一個抽象策略類的子類,
由此可以得出結構類圖如下:

環境類(Context)是需要使用演算法的物件,它在解決某個問題時可以采用多種策略,在環境類中維護一個對抽象策略類的參考實體,用于定義所采用的策略,假如我們不使用策略模式,可能會存在如下代碼:
public class Context {
...
public void algorithm(String type) {
...
if(type == "strategyA") {
// 演算法A
} else if(type == "strategyB") {
// 演算法B
} else if(type == "strategyC") {
// 演算法C
}
...
}
...
}
客戶端要呼叫 Context 類的 algorithm() 方法時,需要根據所傳入的引數來選擇具體演算法,這將導致代碼過于龐大,不利于維護,而且最大的問題是,在環境類中定義演算法,如果需要修改或增加演算法,則勢必要修改源代碼,違反了開閉原則,
導致以上問題的主要原因在于環境類職責過重,即違背了單一職責原則,策略模式正是解決這個問題的好幫手,引入一個抽象策略類(Strategy),在其中定義抽象演算法,每一個繼承它的具體策略類(ConcreteStrategy)使用具體演算法實作某個業務辦理,環境類只針對抽象策略類編程,符合依賴倒轉原則,出現新的演算法時,只需要增加一個新的實作了抽象策略類的具體策略類即可,
public abstract class AbstractStrategy {
public abstract void algorithm();
}
將每一種具體演算法作為該抽象策略類的子類
public class ConcreteStrategyA extends AbstractStrategy {
public void algorithm() {
// 演算法A
}
}
對于環境類,在它與抽象策略類之間建立一個關聯關系
public class Context {
private AbstractStrategy strategy;
public void setStrategy(AbstractStrategy strategy) {
this.strategy = strategy;
}
public void algorithm() {
strategy.algorithm();
}
}
對于用戶而言,使用環境類時只需注入一個具體策略物件即可,用戶可以靈活更換具體策略類,比如使用組態檔,增加新的具體策略類也很方便,因此策略模式相當于“即插即用的演算法”,
需要注意的是,策略模式并不負責“哪一個具體策略類適用于哪一種情況”這個決定,換言之,應當由客戶決定在什么情況下使用什么具體策略角色,一定程度上提高了系統靈活性,但前提是客戶需要理解所有具體策略類之間的區別及最佳使用場景,
模式優缺點
策略模式的優點:
- 策略模式提供了對開閉原則的完美支持,將演算法的使用與實作完美分離,用戶可以在不修改原有系統的基礎上選擇和新增演算法
- 策略模式的等級結構定義了一個演算法族,恰當使用繼承可以把公共的代碼移到父類里面,避免重復代碼
- 可以避免使用多重條件轉移陳述句
策略模式的缺點:
- 客戶端必須知道所有的策略類,并自行決定使用哪一種演算法
- 策略模式將產生很多策略類和物件,可以通過享元模式在一定程度上減少物件的數量
策略模式與狀態模式的比較
由于結構的相似性,所以很容易會把策略模式和狀態模式混肴,但它們是為解決不同的問題而設計的,是完全不同的兩種模式,如何區分是策略模式還是狀態模式?其區別如下:
- 如果環境角色存在多種狀態,而且這些狀態之間可以進行轉換,則應使用狀態模式,在狀態模式在,環境類在生命周期中,會有一個不同的狀態物件被創建和使用;如果環境角色只有一個狀態,那么應當使用策略模式,因為一旦環境角色選擇了一個具體策略類,那么在整個環境類的生命周期里它都不會改變這個具體策略類
- 策略模式的環境類自己選擇一個具體策略類,具體策略類無須關心環境類;狀態模式的環境類與狀態類之間存在一種雙向關系,以便實作狀態的切換
- 使用策略模式,客戶端需要知道所選的具體策略模式是哪一個,而使用狀態模式,客戶端無須關心具體狀態,環境類的狀態會根據用戶的操作自動轉換
- 如果系統中某個類的物件存在多種狀態,不同狀態下行為有差異,而且這些狀態之間可以發送轉換時使用狀態模式;如果某個類的行為存在多種實作方式,而且這些方式可以互換時使用策略模式
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/6010.html
標籤:設計模式
上一篇:建造者模式
下一篇:講清責任鏈模式
