本文經過簡單的模擬鴨子應用作起,在模擬鴨子游戲中,會出現各類鴨子,鴨子能夠游泳、能夠呱呱叫。java
如今客戶想讓鴨子能夠飛行,因而贊成了這個需求,類圖變成了下面這樣算法
這是,可怕的問題發生了,有許多「橡皮鴨子」能夠在遊戲界面飛來飛去,這是在設計上的疏忽,由於在超類上加上fly(),就會致使全部的子類都具有fly(),連那些不應具有fly()的子類也沒法免除。設計模式
我能夠把fly()從超類中取出來,放進一個「Flyable接口」中。這麼一來,只有會飛的鴨子才實現此接口。一樣的方式,也能夠用來設計一個「Quackable接口」,由於不是全部的鴨子都會叫。 測試
咱們知道,並不是「全部」的子類都具備飛行和呱呱叫的行爲,因此繼承並非適當的解決方式。雖然Flyable與Quackable能夠解決「一部分」問題(不會再有會飛的橡皮鴨),可是卻形成代碼沒法複用,這隻能算是從一個惡夢跳進另外一個惡夢 。spa
這個時候咱們想到一個設計原則插件
找出應用中可能須要變化之處,把它們獨立出來,不要和那些不須要變化的代碼混在一塊兒。
咱們知道Duck類內的fly()和quack()會隨着鴨子的不一樣而改變。 設計
下面開始設計鴨子的行爲3d
首先,在Duck類中「加入兩個實例變量」 ,分別爲「flyBehavior」與「quackBehavior」,聲明爲接口類型(而不是具體類實現類型),每一個鴨子對象都會動態地設置這些變量以在運行時引用正確的行爲類型 。code
編寫Duck類orm
public abstract class Duck { //爲行爲接口類型聲明兩個引用變量,全部鴨子類都繼承它們 FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { } abstract void display(); public void performFly() { //委託給行爲類 flyBehavior.fly(); } public void performQuack() { //委託給行爲類 quackBehavior.quack(); } public void swim() { System.out.println("All ducks float, even decoys!"); } }
編寫MallardDuck類
public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public void display() { System.out.println("I'm a real Mallard duck"); } }
編寫ModelDuck類
public class ModelDuck extends Duck { public ModelDuck() { flyBehavior = new FlyNoWay(); quackBehavior = new Quack(); } public void display() { System.out.println("I'm a model duck"); } }
編寫FlyBehavior接口與兩個行爲實現類
FlyBehavior接口
public interface FlyBehavior { public void fly(); }
FlyNoWay
public class FlyNoWay implements FlyBehavior { public void fly() { System.out.println("I can't fly"); } }
FlyWithWings
public class FlyWithWings implements FlyBehavior { public void fly() { System.out.println("I'm flying!!"); } }
編寫QuackBehavior接口與三個實現類
public interface QuackBehavior { public void quack(); }
Quack實現類
public class Quack implements QuackBehavior { public void quack() { System.out.println("Quack"); } }
MuteQuack
public class MuteQuack implements QuackBehavior { public void quack() { System.out.println("<< Silence >>"); } }
Squack
public class Squeak implements QuackBehavior { public void quack() { System.out.println("Squeak"); } }
編寫測試類
public class MiniDuckSimulator { public static void main(String[] args) { MallardDuck mallard = new MallardDuck(); mallard.display(); mallard.performQuack(); mallard.performFly(); Duck model = new ModelDuck(); model.display(); model.performQuack(); model.performFly(); } }
運行結果
Define a family of algorithms,encapsulate each one,and make them interchangeable.(定義一組算法, 將每一個算法都封裝起來, 而且使它們之間能夠互換。 )
通用類圖
策略模式使用的就是面向對象的繼承和多態機制, 很是容易理解和掌握, 咱們再來看看策略模式的三個角色:
實現抽象策略中的操做, 該類含有具體的算法
若是沒有策略模式, 咱們想一想看會是什麼樣子? 一個策略家族有5個策略算法, 一會要使用A策略, 一會要使用B策略, 怎麼設計呢? 使用多重的條件語句? 多重條件語句不易維護, 並且出錯的機率大大加強。 使用策略模式後, 能夠由其餘模塊決定採用何種策略, 策略家族對外提供的訪問接口就是封裝類, 簡化了操做, 同時避免了條件語句判斷。
在現有的系統中增長一個策略太容易了, 只要實現接口就能夠了, 其餘都不用修改, 相似於一個可反覆拆卸的插件, 這大大地符合了OCP原則。
每個策略都是一個類, 複用的可能性很小, 類數量增多。
參考書籍:《Head First 設計模式》《設計模式之禪》