在策略模式(Strategy Pattern)中,一個類的行為或其演算法可以在運行時更改。這種類型的設計模式屬於行為型模式。 在策略模式中,我們創建表示各種策略的對象和一個行為隨著策略對象改變而改變的 context 對象。策略對象改變 context 對象的執行演算法。 <! more 介紹 什麼是策 ...
在策略模式(Strategy Pattern)中,一個類的行為或其演算法可以在運行時更改。這種類型的設計模式屬於行為型模式。
在策略模式中,我們創建表示各種策略的對象和一個行為隨著策略對象改變而改變的 context 對象。策略對象改變 context 對象的執行演算法。
介紹
什麼是策略模式(Strategy Pattern)
在軟體開發過程中常常遇到這樣的情況, 實現某一個功能有很多種演算法或實現策略, 我們可以根據環境或者條件的不同選擇不同的演算法或者策略來完成該功能. 如果將這些演算法或者策略抽象出來, 提供一個統一的介面, 不同的演算法或者策略有不同的實現類, 這樣在程式客戶端就可以通過註入不同的實現對象來實現演算法或者策略的動態替換, 這種模式的可擴展性和可維護性也更高, 這就是策略模式.
策略模式的定義(Strategy Pattern)
策略模式: 定義了演算法族,分別封裝起來,讓它們之間可以相互替換,此模式讓演算法的變化獨立與使用演算法的客戶.(摘抄於Head First設計模式)
簡單理解: 定義了一系列演算法,每個演算法封裝起來,各個演算法之間可以互相替換,且演算法的變化不會影響到使用演算法的客戶,屬於行為型模式.
使用場景
- 針對同一類型問題的多種處理方式,僅僅是具體行為有差別時;
- 需要安全的封裝多種同一類型的操作時;
- 出現同一抽象類有多個字類, 而有需要使用 if-else 或者 switch-case 來選擇具體字類時;
例如:
或出現大量 if-else 判斷時可以使用策略模式優化代碼.
例如電商網站支付方式,一般分為銀聯,微信,支付寶,可以採用策略模式,每一種方式作為一種支付方式的實現,如果哪一個支付方式發生變化,只需要修改對應的實現即可,不需要修改調用的客戶端,如果引入新的支付方式,如:隨行付,則只需要增加一個對應的隨行付實現類即可,遵循開閉原則.
組成部分(三個角色)
1. 抽象策略(Strategy):
通常由介面或抽象類實現. 定義了多個具體策略的公共介面, 具體策略中各種不同的演算法以不同的方式實現這個介面; Context使用這些介面調用不同實現的演算法.
2. 具體策略(ConcreteStrategy):
實現了Strategy介面或繼承與抽象類, 封裝了具體的演算法和行為.
3. 環境類(Context):
持有一個公共策略介面的引用(Strategy), 直接給客戶端調用.
優缺點及重點
優點:
- 每個演算法單獨封裝, 減少演算法與演算法調用者之間的耦合;
- 演算法可以自由切換;
- 避免使用多重條件判斷;
- 擴展性良好;
缺點:
- 策略類會增多.
- 所有策略類都需要對外暴露.
重點
- 給對象傳入什麼樣的策略, 就執行什麼樣的動作.
實現
類圖
說明: 代碼來自Head First設計模式中SimUDuck的示例.
代碼結構:
抽象策略(Strategy):
/**
* 飛行行為
*/
public interface FlyBehavior {
//各種飛行實現
public void fly();
}
具體策略(ConcreteStrategy):
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying!");
}
}
環境類(Context):
/**
* 鴨子類
*/
public abstract class Duck {
//持有一個公共策略介面的引用
public FlyBehavior flyBehavior;
public QuackBehavior quackBehavior;
public void swim() {
System.out.println("我會游泳...");
}
public abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
//提供set方法, 使鴨子可以動態改變飛行策略
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
//提供set方法, 使鴨子可以動態改變叫聲策略
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
/**
* 綠頭鴨
*/
public class MallardDuck extends Duck {
@Override
public void display() {
System.out.println("綠頭鴨");
}
public MallardDuck() {
/*MallardDuck 繼承 Duck, 所以具有quackBehavior 和 flyBehavior實例變數
當MallardDuck實例化時, 它的構造器會把繼承的quackBehavior,
flyBehavior實例變數初始化成Quack,FlyWithWings類型的新實例
*/
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
}
測試類:
public static void main(String[] args) {
Duck mallard = new MallardDuck();
//飛行
mallard.performFly();
//改變鴨子行為(傳入飛行策略)
mallard.setFlyBehavior(new FlyRocketPowered());
mallard.performFly();
//叫聲
mallard.performQuack();
}
執行結果:
I'm flying!
I'm flying with a rocket!
呱呱叫
生活中的策略模式(我的猜想)
俗話說: 人是鐵飯是鋼, 一頓不吃餓的慌;吃飯也有策略模式, 你曉得嘛.
人(環境類)餓了要吃飯(抽象策略), 但是吃什麼你知道嗎? 這時你的大腦就會調集你的畢生功力(經驗, 生活經歷, 常識等等),來知道有哪些東西是可以吃的,比如雞腿,麵包或粥等等(具體策略,暴露所有策略).大腦選擇(動態選擇策略)吃其中的一種或多種食物來應對身體的不滿.
生活中這樣的例子還有很多,網上購物(不同的商品即: 具體策略), 世界那麼大, 我想去轉轉.(轉轉的方式即: 具體策略)等.
結語
設計模式源於生活