據說是程序員工作中用到的最多的模式:策略模式解析

這是從零學習設計模式的第一篇文章,也算是入門篇吧。

大家都知道設計模式很重要,掌握設計模式是一個高級開發乃至架構師都必須要具備的技能。 但是不知道有沒有這樣的感覺,每次看設計模式的概念都差不多能看懂,但是就是不會用,而且不能夠識別一些優秀的代碼具體是運用了什麼設計模式? 最終的結果就是,慢慢的忘記,腦海中的設計模式只是一個很大很虛的概念。

我目前就屬於這種狀態,爲了能夠提高自己的編碼設計能力,在工作中設計出有彈性,好維護,能更好的應付業務變化的代碼,準備認真學習一邊設計模式。

其實大學期間就斷斷續續看過《Head First 設計模式》,但是當時印象也不深刻,工作後也不太會用。 到現在工作快四年了,再次看這本書,感覺真的不一樣,也是因爲工作這幾年有了實戰經驗,慢慢知道了平時開發中的痛點,最後優化形成的解決方案,其實有很多就是用到了設計模式的思想。

目標

作爲 Java 程序員,我們已經進入到對象村,OO思想和設計是已經深入人心的潛規則。 但是 良好的 OO 設計,並不是那麼簡單的,要結合前人大量的實踐經驗總結,不斷的艱苦聯繫才能成功。 而這些前人的經驗就是已經整理好的設計模式。

使用設計模式最好的方式是:“把模式裝進腦子裏,然後在你的設計和已有的應用中,尋找何處可以使用它們”。平時我們做的最多的是代碼複用,而學習設計模式其實是經驗複用。

一定要多回顧、多思考、多實踐,這樣才能深入理解和使用好設計模式。

入門:鴨子系統的設計

中級程序員的設計實現

我們來看一個簡單的例子,鴨子系統的設計嚴謹,去理解設計模式帶來的影響。

有一款模擬鴨子游戲,遊戲中有很多種鴨子,會游泳,會呱呱叫,這時候利用 標準的 OO 技術,設計如下:

繼承來實現

游泳和叫所有鴨子都會,所以爲了代碼複用,在基類中實現,外觀由於各不相同是抽象方法,下沉到子類去實現,ok,符合 OO 思想,到此就結束了? 那隻能說你太年輕。。

需求變更: 主管確定要求遊戲中有會飛的鴨子,這時候你評估需求時,信誓旦旦的說,我們三天搞定。。。嗯。。加下班,明天就可以上線。

畢竟作爲一名 OO 程序員,這沒什麼困難的,你直接在鴨子的基類中添加一個 fly() 方法,然後就被子類繼承了, OO 大顯神功。

但是,這個時候問題出現了,領導在測試環境做體驗的時候,發現以前的 "殭屍鴨子" 居然也在天上飛來飛去,這下炸了,對代碼局部的修改,居然影響到了全局,讓一些沒有生命力的鴨子也會飛上天了。

這個時候,你可能想到繼承,可以在子類中覆蓋父類的實現,將 “殭屍鴨子”的 fly() 非法覆蓋掉,改爲不會飛 。。。

這樣雖然也可以,但是你要想到,如果後續又加入了 “誘餌鴨” 即不會飛也不會叫,這難道也要去其實現中重寫對應的方法??

要知道作程序員,你一定要牢記一個不變的真理,那就是 CHANGE! 不管一開始設計的多麼好,一段時間後,總是需要成長與改變。

到這裏你也發現了,繼承中的缺點是:

  1. 代碼在多個子類中重複;
  2. 運行時的行爲不容易改變,必須通過硬編碼;
  3. 很難知道所有鴨子的全部行爲,不同的子類實現不一樣;
  4. 改一處就會動全身,造成子類鴨子不想要的改變;

把行爲設計成接口

你可能會想到,將飛行行爲和呱呱叫設計爲對應的接口,有對應需要的鴨子直接去實現就好了,雖然這個方法是可以解決問題,但是你要想到,後續鴨子越來越多,每個都需要去實現飛行和呱呱叫接口,這樣得要寫多少重複的代碼,無疑又掉入了另一個坑中。

模式大師來設計

找出應用中可能需要變化的,把它們獨立出來進行封裝

如果找到代碼中可能需要變化的呢?

  1. 每次新需求來了,都會使某方面的代碼發生變化,那麼就可以確定,這部分代碼需要被抽出來,和其他穩定的代碼區分;
  2. 憑藉自己對需求的理解,在一開始設計時將未來需求改變的代碼抽出來封裝;

這其實就是很多設計模式背後的精神所在,也是一種設計原則:“將會變化的部分取出來並封裝起來,以便以後可以輕易地改動或擴充此部分,而不影響不需要變化的其他部分”。

所以,結合鴨子系統的需求,我們可以發現,鴨子的行爲是經常變化的,因爲有的會飛有的不會飛,有的會叫有的不會叫,所以需要抽出來進行封裝。而其他部分還是比較正常的,所以依舊放到 Duck 基類中。

針對接口編程,而不是針對具體實現

上面我們已經知道了要將鴨子的 飛行和呱呱叫行爲 抽出來封裝,那麼該如何實現呢?

我們的設計目標就是一切都有彈性,避免出現 中級開發工程師設計的系統,由於沒有彈性所以纔去請了模式大師出手。

大師將鴨子的行爲設計成接口,如 FlyBehavior、QuackBehavior,這樣行爲就可以動態的擴展,我們可以在鴨子類中包含行爲的方法,然後在 “運行時” 動態的 “改變” 飛行和呱呱叫行爲。

也就是在,大師的設計中,鴨子的子類將使用接口(FlyBehavior 和 QuackBehavior)所表示的行爲,所以實際的實現不會被綁死在鴨子的子類中。

而且我們也可以新增一些行爲,不會影響到既有的飛行和呱呱叫行爲,也不會影響 “使用”到已有行爲的鴨子類,

多用組合,少用繼承

相信這個概念你不是第一次聽到了,組合優於繼承,因爲使用組合建立的系統擁有很大的彈性,可以“在運行時動態的改變行爲”,因爲結合上面的針對接口編程,只要組合的行爲符合接口定義標準即可。

下面我們一起來看下,最終的系統結構:

認真去看下設計圖,代碼應該很好實現了,我就不寫了。

設計模式:策略模式

上面大師的設計,就引出了我們今天要學習的設計模式:策略模式。不要懷疑,正是使用了策略模式改寫了我們的鴨子系統。

策略模式定義了算法簇,分別分裝起來,讓它們之間可以互相轉換,此模式讓算法的變化獨立於使用算法的客戶。

思考與提升

  1. 我們如何使用設計模式?

我們開發中都是使用設計好的庫和框架,這個沒有問題,我們享受着別人代碼的便利性,但是如何組裝到我們的應用系統中,使我們的應用系統變得 易瞭解、容易維護、具有彈性,這個就需要設計模式出馬了。但是設計模式不會直接進入你的代碼中,你要做的就是先讓設計模式進入你的大腦中,這樣在開始新設計又或者當舊代碼一團亂麻時,你就可以運用它們。

  1. 一開始想不到可用的設計模式?

這個是我們初學者必然遇到的問題,別慌,先牢記一些面向對象的原則,因爲它們適用於所有模式,當我們踩過坑,不斷思考這些原則最終的方案往往就是設計模式了。

OO基礎:

  1. 抽象
  2. 封裝
  3. 多態
  4. 繼承

本文設計的OO原則(後續還有更多): 封裝變化 多用組合,少用繼承 針對接口編程,不針對實現編程

OO模式: 策略模式: 定義算法族,分別分裝起來,讓它們之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶

更多精彩文章,可以關注我哦!
掃碼關注

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章