深入淺出設(shè)計模式(一)-策略模式

本文解決問題

  • 什么是策略模式职抡?
  • 策略模式的優(yōu)缺點以及策略模式解決了什么痛點
  • 策略模式的適用環(huán)境

什么是策略模式亩歹?

策略模式(Strategy Pattern):定義一系列算法纫事,將每一個算法封裝起來册着,并讓它們可以相互替換褐着。策略模式讓算法獨立于使用它的客戶而變化,也稱為政策模式(Policy)豆挽。

策略模式是一種對象行為型模式育谬。

策略模式的類圖

說定義恐怕總會令人迷惑,其實這里的算法就是我們?nèi)粘Kf的行為帮哈,舉個栗子:

這是一個模擬鴨子游戲:游戲中會出現(xiàn)各種鴨子膛檀,一邊游泳,一邊叫娘侍。

這個應(yīng)用用的是OO技術(shù)有一個鴨子超類(superclass)宿刮,并讓各種鴨子繼承此類。

public abstract class Duck {
    public Duck() {}
  
    abstract void display();
  
    public void quack() {}

    public void swim() {}
}

public class MallardDuck extends Duck {
    //外觀是綠頭鴨
    public MallardDuck() {}

    public void display() {}
}

public class RedHeadDuck extends Duck {
 
    public RedHeadDuck() {}
 
    public void display() {}
}

但是產(chǎn)品經(jīng)理組織了一場頭腦風暴私蕾,然后決定要讓鴨子們會飛,我們怎么做胡桃?程序猿們說 很簡單于是

public class Duck {
    public Duck() {}
  
    public void quack() {}

    public void swim() {}
  
    public void fly(){}
}

所有的鴨子都會飛了踩叭,但是……,他們的游戲里面有一只橡皮鴨翠胰,產(chǎn)品經(jīng)理攤手表示容贝,橡皮鴨是為什么會飛的。之景。斤富。。這時候你會怎么辦锻狗?

OO來說我們繼承覆蓋就好了

public class RubberDuck extends Duck {
  public void display() {};
  
  public void quack(){};
    
  public void fly(){
    //什么都不做
  }
}

但是如果以后加入鐵鴨子怎么辦满力?不會飛也不會叫

那下面我們用OO中的接口如何?也就是說把fly()quack()寫成接口轻纪,下面的鴨子進行繼承油额。會有什么問題呢?

如果是你你會怎么辦刻帚?

采用良好的00軟件設(shè)計原則:

  1. 原則一:

找出應(yīng)用中可能需要變化的地方潦嘶,把它們獨立出來,不要和那些不需要變化的代碼混在一起崇众,這時候你就可以很好的修改或者擴展這部分掂僵,而不影響不需要變化的其他部分航厚。

到底哪一些是Duck類變得以及不變的?

  • fly()與quack()會隨著不同而改變
  • 你沒有辦法開始就知道锰蓬,但是可以再改需求的時候慢慢修改提煉
  1. 原則二:

針對接口編程幔睬,而不是針對實現(xiàn)編程

這個對于我們OO來說很需要了解,我目前總是針對實現(xiàn)編程而不是接口編程互妓。在栗子中怎么實現(xiàn)呢溪窒?那就是鴨子的行為將被放在分開的類中,專門提供某行為的接口的實現(xiàn)冯勉,鴨子的類就不需要知道行為的實現(xiàn)細節(jié)

舉個栗子:

public interface FlyBehavior {
    public void fly();
}

public class FlyWithWings implements FlyBehavior {
    public void fly() {
        System.out.println("I'm flying!!");
    }
}

public class FlyNoWay implements FlyBehavior {
    public void fly() {
        System.out.println("I can't fly");
    }
}

public interface QuackBehavior {
    public void quack();
}

public class Quack implements QuackBehavior {
    public void quack() {
      //呱呱叫
        System.out.println("Quack");
    }
}

public class Squeak implements QuackBehavior {
    public void quack() {
      //橡皮鴨子吱吱叫
        System.out.println("Squeak");
    }
}

public class MuteQuack implements QuackBehavior {
    public void quack() {
      //什么都不做澈蚌,我不會叫
        System.out.println("<< Silence >>");
    }
}

那這些有什么好處?對了行為單獨一個類灼狰,實現(xiàn)了解耦宛瞄,這些行為和鴨子無關(guān)了,以后Nathan要什么的鴨子交胚,我們程序猿都可以給他了份汗。

這時候有個問題,我們要在什么時候分離封裝呢蝴簇?

解耦很清晰杯活,可是我們要怎么整合起來呢?讓鴨子更像一個鴨子熬词,先要在duck加兩個實體變量

public abstract class Duck {
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;
  
    abstract void display();

    public void performFly() {
        flyBehavior.fly();
    }

    public void performQuack() {
        quackBehavior.quack();
    }

    public void swim() {
        System.out.println("All ducks float, even decoys!");
    }
}


public class MallardDuck extends Duck {

    public MallardDuck() {
      //在構(gòu)造綠頭鴨的時候裝配上叫和飛的行為旁钧,這個綠頭鴨就真的會飛和叫了
        quackBehavior = new Quack();
        flyBehavior = new FlyWithWings();
    }

    public void display() {
        System.out.println("I'm a real Mallard duck");
    }
}

編寫好了,如何測試呢互拾?

public class MiniDuckSimulator {

    public static void main(String[] args) {
 
        MallardDuck mallard = new MallardDuck();
        RubberDuck  rubberDuckie = new RubberDuck();
        DecoyDuck   decoy = new DecoyDuck();
 
        mallard.performQuack();
        rubberDuckie.performQuack();
        decoy.performQuack();
    }
}

講了這么多歪今,我們從新的梳理一下,到底整體的一個架構(gòu)是什么樣子的颜矿,這時候請不要把鴨子的行為說成行為寄猩,我們把行為想象成一族算法,這樣行為是不是就可以放在很多地方了骑疆?

  1. 原則三

多用組合田篇,少用繼承。

上面我們看了組合建立系統(tǒng)的具有很大的彈性封断,可以把算法族封裝成類斯辰,還可以隨意組合,只要符合正確的接口坡疼。

以后要做什么捕捉鴨子的鴨鳴器繼承一個算法就可以很快實現(xiàn)彬呻。

上述其實講解OO原則的時候你已經(jīng)學(xué)會了策略模式。

策略模式的優(yōu)點

  • 策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統(tǒng)的基礎(chǔ)上選擇算法或行為闸氮,也可以靈活地增加新的算法或行為剪况。
  • 策略模式提供了管理相關(guān)的算法族的辦法。
  • 策略模式提供了可以替換繼承關(guān)系的辦法蒲跨。
  • 使用策略模式可以避免使用多重條件轉(zhuǎn)移語句译断。

策略模式的缺點

  • 客戶端必須知道所有的策略類,并自行決定使用哪一個策略類或悲。
  • 策略模式將造成產(chǎn)生很多策略類孙咪,可以通過使用享元模式在一定程度上減少對象的數(shù)量。

策略模式的適用范圍

做面向?qū)ο笤O(shè)計的巡语,對策略模式一定很熟悉翎蹈,因為它實質(zhì)上就是面向?qū)ο笾械睦^承和多態(tài),在看完策略模式的通用代碼后男公,我想荤堪,即使之前從來沒有聽說過策略模式,在開發(fā)過程中也一定使用過它吧枢赔?至少在在以下兩種情況下澄阳,大家可以考慮使用策略模式,

  • 幾個類的主要邏輯相同踏拜,只在部分邏輯的算法和行為上稍有區(qū)別的情況碎赢。
  • 有幾種相似的行為,或者說算法速梗,客戶端需要動態(tài)地決定使用哪一種揩抡,那么可以使用策略模式,將這些算法封裝起來供客戶端調(diào)用镀琉。

? 策略模式是一種簡單常用的模式,我們在進行開發(fā)的時候蕊唐,會經(jīng)常有意無意地使用它屋摔,一般來說,策略模式不會單獨使用替梨,跟模版方法模式钓试、工廠模式等混合使用的情況比較多。

  • 如果在一個系統(tǒng)里面有許多類副瀑,它們之間的區(qū)別僅在于它們的行為弓熏,那么使用策略模式可以動態(tài)地讓一個對象在許多行為中選擇一種行為。
  • 一個系統(tǒng)需要動態(tài)地在幾種算法中選擇一種糠睡。
  • 如果一個對象有很多的行為挽鞠,如果不用恰當?shù)哪J剑@些行為就只好使用多重的條件選擇語句來實現(xiàn)。
  • 不希望客戶端知道復(fù)雜的信认、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)材义,在具體策略類中封裝算法和相關(guān)的數(shù)據(jù)結(jié)構(gòu),提高算法的保密性與安全性嫁赏。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末其掂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子潦蝇,更是在濱河造成了極大的恐慌款熬,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攘乒,死亡現(xiàn)場離奇詭異贤牛,居然都是意外死亡,警方通過查閱死者的電腦和手機持灰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門盔夜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人堤魁,你說我怎么就攤上這事喂链。” “怎么了妥泉?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵椭微,是天一觀的道長。 經(jīng)常有香客問我盲链,道長蝇率,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任刽沾,我火速辦了婚禮本慕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘侧漓。我一直安慰自己锅尘,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布布蔗。 她就那樣靜靜地躺著藤违,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纵揍。 梳的紋絲不亂的頭發(fā)上顿乒,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音泽谨,去河邊找鬼璧榄。 笑死特漩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的犹菱。 我是一名探鬼主播拾稳,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腊脱!你這毒婦竟也來了访得?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤陕凹,失蹤者是張志新(化名)和其女友劉穎悍抑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杜耙,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡搜骡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了佑女。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片记靡。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖团驱,靈堂內(nèi)的尸體忽然破棺而出摸吠,到底是詐尸還是另有隱情,我是刑警寧澤嚎花,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布寸痢,位于F島的核電站,受9級特大地震影響紊选,放射性物質(zhì)發(fā)生泄漏啼止。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一兵罢、第九天 我趴在偏房一處隱蔽的房頂上張望献烦。 院中可真熱鬧,春花似錦卖词、人聲如沸仿荆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至锦亦,卻和暖如春舶替,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杠园。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工顾瞪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓陈醒,卻偏偏與公主長得像惕橙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钉跷,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 深入淺出設(shè)計模式(1)-策略模式 講義要解決問題 什么是設(shè)計模式弥鹦? 為什么23種設(shè)計模式中沒有MVC模式 一些OO...
    慕久久閱讀 475評論 0 1
  • 1 場景問題# 1.1 報價管理## 向客戶報價,對于銷售部門的人來講爷辙,這是一個非常重大彬坏、非常復(fù)雜的問題,對不同的...
    七寸知架構(gòu)閱讀 5,064評論 9 62
  • 1 場景問題 1.1 報價管理 向客戶報價膝晾,對于銷售部門的人來講栓始,這是一個非常重大、非常復(fù)雜的問題血当,對不同的客戶要...
    4e70992f13e7閱讀 3,073評論 2 16
  • 創(chuàng)建模式單例模式工廠模式 結(jié)構(gòu)型模式代理模式適配器模式 行為型模式觀察者模式責任鏈模式策略模式模板方法模式 創(chuàng)建模...
    百里少龍閱讀 506評論 0 1
  • 設(shè)計模式匯總 一幻赚、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,922評論 1 15