[head first 設計模式] 第一章 策略模式

[head first 設計模式] 第一章 策略模式

讓我們先從一個簡單的鴨子模擬器開始講起部蛇。

假設有個簡單的鴨子模擬器杏愤,游戲中會出現(xiàn)各種鴨子,此系統(tǒng)的原始設計如下牙言,設計了一個鴨子超類辆毡,并讓各種鴨子繼承此超類菜秦。

1.jpg

若此時我們有了一個新的需求,我們需要鴨子會飛舶掖,那么我們該如何修改代碼呢球昨?

最初,我們想在基類上加上fly方法眨攘,使得所有子類鴨子都擁有相應的fly方法主慰。但這樣錯誤產(chǎn)生了嚣州,即使是本不該會飛的橡皮鴨子也擁有了fly方法。

或許我們可以把橡皮鴨中的fly方法覆蓋掉共螺,但這樣每次新加入的不會飛的新鴨子類型该肴,難道都要額外覆蓋一次fly方法嗎?太麻煩了藐不。

利用繼承來提供duck的行為匀哄,會導致運行時的行為不容易改變,且改變容易牽一發(fā)動全身雏蛮。

那么涎嚼,利用接口如何?

若經(jīng)常需要更新產(chǎn)品,那么每次覆蓋fly簡直是噩夢挑秉。那么法梯,我們將fly單獨寫成一個接口,只有會飛的鴨子實現(xiàn)這個接口如何衷模?

2.jpg

但這樣其實重復的代碼會變得非常多鹊汛,造成fly代碼無法復用蒲赂,每個會飛的鴨子都要實現(xiàn)fly方法阱冶。

那么我們該如何解決這個問題?在使用設計模式之前滥嘴,不妨先求索于OO原則木蹬!

軟件開發(fā)中,什么是永恒真理若皱?

唯一不變的是變化本身——約翰遜·斯賓塞

現(xiàn)在我們已經(jīng)知道了繼承無法很好的解決問題镊叁,因為鴨子的行為在子類中不斷改變,并且有的行為子類不應該擁有走触。使用接口初看挺不錯的晦譬,但繼承接口無法達到代碼的復用。這意味著互广,無論合適你需要修改某個行為敛腌,你必須向下追蹤并在每一個定義此行為的類中修改它。

但還好惫皱,有一個OO設計原則正好適用于此種情況:

找出系統(tǒng)中可能需要變化之處像樊,把他們獨立出來,不要和那些不變化的代碼堆在一起旅敷。

也就是把會變化的部分取出來生棍,好讓其他部分不會受此影響。

把會變化的部分取出來并封裝媳谁,以后可以輕易地改動或擴充此部分涂滴,而不影響其他不需要變化的部分友酱。

那么,現(xiàn)在是時候把鴨子的行為從Duck類中取出了氢妈。

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

目前而言粹污,除了fly()和quack()以外,duck類其他部分看起來不怎么變動首量,所以我們僅做些小改變壮吩。

為此,我們準備建立兩組類加缘,一個是和fly相關的鸭叙,另一個和quack相關的,每一組類都實現(xiàn)各自的動作拣宏。

3.jpg

設計鴨子的行為

如何設計

那組實現(xiàn)飛行和叫聲的類呢沈贝?我們希望一切能有彈性,并且能夠將行為指定到鴨子的實例勋乾。并且可以讓鴨子的行為動態(tài)的改變宋下。

有了這些目標要實現(xiàn),我們看第二個設計原則

針對接口編程辑莫,而不是針對實現(xiàn)編程学歧。

從現(xiàn)在開始,鴨子的行為將被放在分開的類中各吨,此類專門提供某行為接口的實現(xiàn)枝笨。這樣,鴨子類就不再需要知道行為的具體細節(jié)揭蜒。

這次鴨子類不會負責實現(xiàn)flying和quacking接口横浑,而是由我們制造一組其他類專門實現(xiàn)flybehavior和quackbeavior,這就稱為行為類屉更,由行為類而不是duck類來實現(xiàn)行為接口徙融。

這種做法和以往不同,以往是行為來自于duck超類的具體實現(xiàn)瑰谜,或是繼承某個接口并由子類自行實現(xiàn)而來欺冀。這兩種方法都是依賴于實現(xiàn),沒法變更行為似舵。

在我們的新設計中脚猾,鴨子的子類將使用接口所表示的行為,所以具體的實現(xiàn)不會被綁定在鴨子的子類中砚哗。

4.jpg

整合鴨子的行為

關鍵在于龙助,鴨子會將飛行和叫聲行為委托給其他對象處理。而不是由自己定義。

在Duck類中加入flyBehavior和quackBehavior變量提鸟,聲明為接口類型军援。每個鴨子對象動態(tài)設置這些變量以在運行時引用正確的行為類型。

代碼如下

public interface FlyBehavior {
    public void fly();
}
public interface QuackBehavior {
    public void quack();
}
public class FlyWithWings implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("I'm flying");
    }
}
public class FlyNoWay implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("I can't fly");
    }
}
public class Quack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("quack!");
    }
}
public class MuteQuack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("<<silence>>");
    }
}
public class Squeak implements QuackBehavior{

    @Override
    public void quack() {
        System.out.println("Squeak!");
    }
}
public abstract class Duck {
    protected FlyBehavior flyBehavior;
    protected  QuackBehavior quackBehavior;
    abstract void display();
    public void performFly()
    {
        flyBehavior.fly();
    }
    public void performQuack()
    {
        quackBehavior.quack();
    }
}
public class MallardDuck extends Duck{
    @Override
    public void display() {
        System.out.println("I'm a real mallard duck");
    }
    public MallardDuck(){
        flyBehavior = new FlyWithWings();
        quackBehavior  = new Quack();
    }
}
public class MiniDuckSimulator {
    public static void main(String[] args) {
        Duck mallardDuck = new MallardDuck();
        mallardDuck.performFly();
        mallardDuck.performQuack();
    }
}

動態(tài)設定行為

在鴨子子類中為兩個behavior加入set方法称勋,而不是在構造器中進行實例化胸哥。有了這個,我們就能在運行時隨時改變鴨子的行為赡鲜。


    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

整體設計

現(xiàn)在我們來看看整體結構

5.jpg

我們不再把鴨子的行為說成是行為空厌,而是一族算法。算法代表鴨子能做的事情银酬。在本例中嘲更,我們鴨子的行為是組合來的,而不是繼承來的揩瞪。

我們得到第三個OO設計原則

多用組合赋朦,少用繼承

學習完以上部分,我們正式定義策略模式

6.jpg
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末李破,一起剝皮案震驚了整個濱河市宠哄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嗤攻,老刑警劉巖毛嫉,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異屯曹,居然都是意外死亡狱庇,警方通過查閱死者的電腦和手機惊畏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門恶耽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颜启,你說我怎么就攤上這事偷俭。” “怎么了缰盏?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵涌萤,是天一觀的道長。 經(jīng)常有香客問我口猜,道長负溪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任济炎,我火速辦了婚禮川抡,結果婚禮上,老公的妹妹穿的比我還像新娘须尚。我一直安慰自己崖堤,他們只是感情好侍咱,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著密幔,像睡著了一般楔脯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胯甩,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天昧廷,我揣著相機與錄音,去河邊找鬼偎箫。 笑死麸粮,一個胖子當著我的面吹牛,可吹牛的內容都是我干的镜廉。 我是一名探鬼主播弄诲,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼娇唯!你這毒婦竟也來了齐遵?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤塔插,失蹤者是張志新(化名)和其女友劉穎梗摇,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體想许,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡伶授,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了流纹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劫瞳。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡筛武,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情澜掩,我是刑警寧澤麻车,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布伯铣,位于F島的核電站崎坊,受9級特大地震影響,放射性物質發(fā)生泄漏壁公。R本人自食惡果不足惜感论,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望紊册。 院中可真熱鬧比肄,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至示括,卻和暖如春铺浇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背垛膝。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工鳍侣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吼拥。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓倚聚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凿可。 傳聞我的和親對象是個殘疾皇子惑折,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內容