設計模式----策略模式

本文經過簡單的模擬鴨子應用作起,在模擬鴨子游戲中,會出現各類鴨子,鴨子能夠游泳、能夠呱呱叫。java


看看模擬鴨子程序的初期類圖

image-20200531150923842

如今客戶想讓鴨子能夠飛行,因而贊成了這個需求,類圖變成了下面這樣算法

image-20200531151256672

這是,可怕的問題發生了,有許多「橡皮鴨子」能夠在遊戲界面飛來飛去,這是在設計上的疏忽,由於在超類上加上fly(),就會致使全部的子類都具有fly(),連那些不應具有fly()的子類也沒法免除。設計模式


利用接口如何?

我能夠把fly()從超類中取出來,放進一個「Flyable接口」中。這麼一來,只有會飛的鴨子才實現此接口。一樣的方式,也能夠用來設計一個「Quackable接口」,由於不是全部的鴨子都會叫。 測試

image-20200531151841312

咱們知道,並不是「全部」的子類都具備飛行和呱呱叫的行爲,因此繼承並非適當的解決方式。雖然Flyable與Quackable能夠解決「一部分」問題(不會再有會飛的橡皮鴨),可是卻形成代碼沒法複用,這隻能算是從一個惡夢跳進另外一個惡夢 。spa

這個時候咱們想到一個設計原則插件

找出應用中可能須要變化之處,把它們獨立出來,不要和那些不須要變化的代碼混在一塊兒。

分開變化和不會變化的部分

咱們知道Duck類內的fly()和quack()會隨着鴨子的不一樣而改變。 設計

下面開始設計鴨子的行爲3d

image-20200531152351585


整合鴨子的行爲

首先,在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();
    }
}

運行結果

image-20200531162244767


策略模式的定義

Define a family of algorithms,encapsulate each one,and make them interchangeable.(定義一組算法, 將每一個算法都封裝起來, 而且使它們之間能夠互換。 )

通用類圖

image-20200531162828790

策略模式使用的就是面向對象的繼承和多態機制, 很是容易理解和掌握, 咱們再來看看策略模式的三個角色:

  • Context封裝角色
    它也叫作上下文角色, 起承上啓下封裝做用, 屏蔽高層模塊對策略、 算法的直接訪問,封裝可能存在的變化。
  • Strategy抽象策略角色
    策略、 算法家族的抽象, 一般爲接口, 定義每一個策略或算法必須具備的方法和屬性。 各位看官可能要問了, 類圖中的AlgorithmInterface是什麼意思, 嘿嘿, algorithm是「運算法則」的意思, 結合起來意思就明白了吧。
  • ConcreteStrategy具體策略角色

    實現抽象策略中的操做, 該類含有具體的算法

策略模式的應用

策略模式的優勢

  • 算法能夠自由切換
  • 避免使用多重條件判斷

    若是沒有策略模式, 咱們想一想看會是什麼樣子? 一個策略家族有5個策略算法, 一會要使用A策略, 一會要使用B策略, 怎麼設計呢? 使用多重的條件語句? 多重條件語句不易維護, 並且出錯的機率大大加強。 使用策略模式後, 能夠由其餘模塊決定採用何種策略, 策略家族對外提供的訪問接口就是封裝類, 簡化了操做, 同時避免了條件語句判斷。

  • 擴展性良好

    在現有的系統中增長一個策略太容易了, 只要實現接口就能夠了, 其餘都不用修改, 相似於一個可反覆拆卸的插件, 這大大地符合了OCP原則。

策略模式的缺點

  • 策略類數量增多

    每個策略都是一個類, 複用的可能性很小, 類數量增多。

  • 全部的策略類都須要對外暴露

策略模式的使用場景

  • 多個類只有在算法或行爲上稍有不一樣的場景
  • 算法須要自由切換的場景
    例如, 算法的選擇是由使用者決定的, 或者算法始終在進化, 特別是一些站在技術前沿的行業, 連業務專家都沒法給你保證這樣的系統規則可以存在多長時間, 在這種狀況下策略模式是你最好的助手。
  • 須要屏蔽算法規則的場景

參考書籍:《Head First 設計模式》《設計模式之禪》

相關文章
相關標籤/搜索