## 引入
在閻宏博士的《JAVA與模式》一書中開頭是這樣描述策略(Strategy)模式的:
> 策略模式屬于對象的行為模式。其用意是針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以相互替換。策略模式使得算法可以在不影響到客戶端的情況下發生變化。
在軟件系統中有很多種方法可以實現同一個功能,比如排序算法它有冒泡排序、選擇排序、快速排序、插入排序等等。這里我們有一種硬編碼方法,就是講所以的排序算法全部寫在一個類中,每一種算法的具體實現對應著一個方法,然后寫一個總方法通過if…else…來判斷選擇具體的排序算法,但是這樣做存在幾個問題。
* 第一:如果需要增加新的算法,則需要修改源代碼。
* 第二:如果更新了排序算法,那么需要在客戶端也需要修改代碼,麻煩。
* 第三:充斥著大量的if…else…語句,代碼維護比較困難。
所以為了解決這些問題,我們可以定義一些獨立的類來封裝不同的算法,每一個獨立的類對應著一個具體的算法實現,在這里我們就將這里每一個獨立的類稱之為一個策略。
## 定義
所謂策略模式就是定義了算法族,分別封裝起來,讓他們之前可以互相轉換,此模式然該算法的變化獨立于使用算法的客戶。
## 結構
策略模式是對算法的包裝,是把使用算法的責任和算法本身分割開來,委派給不同的對象管理。策略模式通常把一個系列的算法包裝到一系列的策略類里面,作為一個抽象策略類的子類。用一句話來說,就是:“準備一組算法,并將每一個算法封裝起來,使得它們可以互換”。下面就以一個示意性的實現講解策略模式實例的結構。

這個模式涉及到三個角色:
* 環境(Context)角色:持有一個Strategy的引用。
* 抽象策略(Strategy)角色:這是一個抽象角色,通常由一個接口或抽象類實現。此角色給出所有的具體策略類所需的接口。
* 具體策略(ConcreteStrategy)角色:包裝了相關的算法或行為。
## 代碼實現
場景如下,劉備要到江東娶老婆了,走之前諸葛亮給趙云三個錦囊妙計,說是按天機拆開能解決棘手問題。場景中出現三個要素:三個妙計(具體策略類)、一個錦囊(環境類)、趙云(調用者)。
抽象策略類(Strategy)
~~~
public interface Strategy {
public void operate();
}
~~~
三個實現類(ConcreteStrategy):
妙計一:初到吳國
~~~
public class BackDoor implements IStrategy {
@Override
public void operate() {
System.out.println("找喬國老幫忙,讓吳國太給孫權施加壓力,使孫權不能殺劉備");
}
}
~~~
妙計二:求吳國太開綠燈放行
~~~
public class GivenGreenLight implements IStrategy {
@Override
public void operate() {
System.out.println("求吳國太開個綠燈,放行");
}
}
~~~
妙計三:孫夫人斷后,擋住追兵
~~~
public class BlackEnemy implements IStrategy {
@Override
public void operate() {
System.out.println("孫夫人斷后,擋住追兵");
}
}
~~~
環境類(Context)
~~~
public class Context {
private Strategy strategy;
//構造函數,要你使用哪個妙計
public Context(Strategy strategy){
this.strategy = strategy;
}
public void setStrategy(Strategy strategy){
this.strategy = strategy;
}
public void operate(){
this.strategy.operate();
}
}
~~~
下面就是使用的情況了
~~~
public class Zhaoyun {
public static void main(String[] args) {
Context context;
System.out.println("----------剛到吳國使用第一個錦囊---------------");
context = new Context(new BackDoor());
context.operate();
System.out.println("\n");
System.out.println("----------劉備樂不思蜀使用第二個錦囊---------------");
context.setStrategy(new GivenGreenLight());
context.operate();
System.out.println("\n");
System.out.println("----------孫權的追兵來了,使用第三個錦囊---------------");
context.setStrategy(new BlackEnemy());
context.operate();
System.out.println("\n");
}
}
~~~
以上就是策略模式,多種不同解決方案動態切換,起到改變對象行為的效果。
## 認識策略模式
**策略模式的重心**
策略模式的重心不是如何實現算法,而是如何組織、調用這些算法,從而讓程序結構更靈活,具有更好的維護性和擴展性。
**算法的平等性**
策略模式一個很大的特點就是各個策略算法的平等性。對于一系列具體的策略算法,大家的地位是完全一樣的,正因為這個平等性,才能實現算法之間可以相互替換。所有的策略算法在實現上也是相互獨立的,相互之間是沒有依賴的。
所以可以這樣描述這一系列策略算法:策略算法是相同行為的不同實現。
**運行時策略的唯一性**
運行期間,策略模式在每一個時刻只能使用一個具體的策略實現對象,雖然可以動態地在不同的策略實現中切換,但是同時只能使用一個。
**公有的行為**
經常見到的是,所有的具體策略類都有一些公有的行為。這時候,就應當把這些公有的行為放到共同的抽象策略角色Strategy類里面。當然這時候抽象策略角色必須要用Java抽象類實現,而不能使用接口。
這其實也是典型的將代碼向繼承等級結構的上方集中的標準做法。

## 優點
* 1、策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行為族。恰當使用繼承可以把公共的代碼移到父類里面,從而避免代碼重復。
* 2、使用策略模式可以避免使用多重條件(if-else)語句。多重條件語句不易維護,它把采取哪一種算法或采取哪一種行為的邏輯與算法或行為的邏輯混合在一起,統統列在一個多重條件語句里面,比使用繼承的辦法還要原始和落后。
## 缺點
* 1、客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意味著客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用于客戶端知道算法或行為的情況。
* 2、由于策略模式把每個具體的策略實現都單獨封裝成為類,如果備選的策略很多的話,那么對象的數目就會很可觀。
## 使用場景
* 1、如果在一個系統里面有許多類,它們之間的區別僅在于它們的行為,那么使用策略模式可以動態地讓一個對象在許多行為中選擇一種行為。
* 2、一個系統需要動態地在幾種算法中選擇一種。
* 3、如果一個對象有很多的行為,如果不用恰當的模式,這些行為就只好使用多重的條件選擇語句來實現。
- java
- 設計模式
- 設計模式總覽
- 設計原則
- 工廠方法模式
- 抽象工廠模式
- 單例模式
- 建造者模式
- 原型模式
- 適配器模式
- 裝飾者模式
- 代理模式
- 外觀模式
- 橋接模式
- 組合模式
- 享元模式
- 策略模式
- 模板方法模式
- 觀察者模式
- 迭代子模式
- 責任鏈模式
- 命令模式
- 備忘錄模式
- 狀態模式
- 訪問者模式
- 中介者模式
- 解釋器模式
- 附錄
- JVM相關
- JVM內存結構
- Java虛擬機的內存組成以及堆內存介紹
- Java堆和棧
- 附錄-數據結構的堆棧和內存分配的堆區棧區的區別
- Java內存之Java 堆
- Java內存之虛擬機和內存區域概述
- Java 內存之方法區和運行時常量池
- Java 內存之直接內存(堆外內存)
- JAVA內存模型
- Java內存模型介紹
- 內存模型如何解決緩存一致性問題
- 深入理解Java內存模型——基礎
- 深入理解Java內存模型——重排序
- 深入理解Java內存模型——順序一致性
- 深入理解Java內存模型——volatile
- 深入理解Java內存模型——鎖
- 深入理解Java內存模型——final
- 深入理解Java內存模型——總結
- 內存可見性
- JAVA對象模型
- JVM內存結構 VS Java內存模型 VS Java對象模型
- Java的對象模型
- Java的對象頭
- HotSpot虛擬機
- HotSpot虛擬機對象探秘
- 深入分析Java的編譯原理
- Java虛擬機的鎖優化技術
- 對象和數組并不是都在堆上分配內存的
- 垃圾回收
- JVM內存管理及垃圾回收
- JVM 垃圾回收器工作原理及使用實例介紹
- JVM內存回收理論與實現(對象存活的判定)
- JVM參數及調優
- CMS GC日志分析
- JVM實用參數(一)JVM類型以及編譯器模式
- JVM實用參數(二)參數分類和即時(JIT)編譯器診斷
- JVM實用參數(三)打印所有XX參數及值
- JVM實用參數(四)內存調優
- JVM實用參數(五)新生代垃圾回收
- JVM實用參數(六) 吞吐量收集器
- JVM實用參數(七)CMS收集器
- JVM實用參數(八)GC日志
- Java性能調優原則
- JVM 優化經驗總結
- 面試題整理
- 面試題1
- java日志規約
- Spring安全
- OAtuth2.0簡介
- Spring Session 簡介(一)
- Spring Session 簡介(二)
- Spring Session 簡介(三)
- Spring Security 簡介(一)
- Spring Security 簡介(二)
- Spring Security 簡介(三)
- Spring Security 簡介(四)
- Spring Security 簡介(五)
- Spring Security Oauth2 (一)
- Spring Security Oauth2 (二)
- Spring Security Oauth2 (三)
- SpringBoot
- Shiro
- Shiro和Spring Security對比
- Shiro簡介
- Session、Cookie和Cache
- Web Socket
- Spring WebFlux