軟件設計模式學習(二十五)策略模式


策略模式用於算法的自由切換和擴展,實現了算法定義和算法分離的使用html


模式動機

要完成一項任務,能夠有多種不一樣的方式,例如人們外出旅遊時能夠選擇多種不一樣的出行方式,如自行車、坐汽車、坐高鐵或乘飛機等,每一種方式稱爲一個策略,咱們能夠根據環境或者條件的不一樣選擇不一樣的策略來完成該任務。java

在實際的軟件開發中,一項功能也有不少算法能夠實現,若是咱們直接把多種算法集中在一個類,或者說使用條件判斷語句來進行選擇,無疑會增長代碼複雜性,不利於維護。算法

爲了解決這些問題,能夠定義一些獨立的類來封裝不一樣的算法,每一類封裝一個具體的算法,將每個封裝算法的類稱之爲策略(Strategy)。爲了保證策略的一致性,通常會用一個抽象的策略類來作算法的定義,每種具體算法對應於一個具體策略類。編程


模式定義

策略模式(Strategy Pattern)定義一系列算法,將每一個算法封裝起來,並讓它們能夠相互替換。策略模式讓算法獨立於使用它的客戶而變化,也稱政策模式(Policy)。策略模式是一種對象行爲模式。this

Define a famliy of algorithms, encapsulate each one,and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.設計


模式分析

說到策略模式就不得不提一下狀態模式了,一個是對狀態的封裝,另外一個則是對算法的封裝,所以實現方式上二者有許多共同點,理解起來並不複雜code

點這裏瞭解狀態模式htm

策略模式是對算法的封裝,把算法的責任和算法自己分割開來,委託給不一樣對象管理。策略模式一般把一系列算法封裝到一系列的策略類裏面,做爲一個抽象策略類的子類。對象

由此能夠得出結構類圖以下:blog

環境類(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();
    }
}

對於用戶而言,使用環境類時只需注入一個具體策略對象便可。用戶能夠靈活更換具體策略類,好比使用配置文件,增長新的具體策略類也很方便,所以策略模式至關於「即插即用的算法」。

須要注意的是,策略模式並不負責「哪個具體策略類適用於哪種狀況」這個決定,換言之,應當由客戶決定在什麼狀況下使用什麼具體策略角色,必定程度上提升了系統靈活性,但前提是客戶須要理解因此具體策略類之間的區別及最佳使用場景。

對比狀態模式,狀態模式能夠實現自主的狀態切換,並根據狀態的不一樣作出不一樣的行爲。而


模式優缺點

策略模式的優勢:

  • 策略模式提供了對開閉原則的完美支持,將算法的使用與實現完美分離,用戶能夠在不修改原有系統的基礎上選擇和新增算法
  • 策略模式的等級結構定義了一個算法族,恰當使用繼承能夠把公共的代碼移到父類裏面,避免重複代碼
  • 能夠避免使用多重條件轉移語句

策略模式的缺點:

  • 客戶端必須知道全部的策略類,並自行決定使用哪種算法
  • 策略模式將產生不少策略類和對象,能夠經過享元模式在必定程度上減小對象的數量

策略模式與狀態模式的比較

因爲結構的類似性,因此很容易會把策略模式和狀態模式混餚,但它們是爲解決不一樣的問題而設計的,是徹底不一樣的兩種模式。如何區分是策略模式仍是狀態模式?其區別以下:

  • 若是環境角色存在多種狀態,並且這些狀態之間能夠進行轉換,則應使用狀態模式,在狀態模式在,環境類在生命週期中,會有一個不一樣的狀態對象被建立和使用;若是環境角色只有一個狀態,那麼應當使用策略模式,由於一旦環境角色選擇了一個具體策略類,那麼在整個環境類的生命週期裏它都不會改變這個具體策略類
  • 策略模式的環境類本身選擇一個具體策略類,具體策略類無須關心環境類;狀態模式的環境類與狀態類之間存在一種雙向關係,以便實現狀態的切換
  • 使用策略模式,客戶端須要知道所選的具體策略模式是哪個,而使用狀態模式,客戶端無須關心具體狀態,環境類的狀態會根據用戶的操做自動轉換
  • 若是系統中某個類的對象存在多種狀態,不一樣狀態下行爲有差別,並且這些狀態之間能夠發送轉換時使用狀態模式;若是某個類的行爲存在多種實現方式,並且這些方式能夠互換時使用策略模式
相關文章
相關標籤/搜索