如影隨形的設計模式與現實世界
來自專欄猿論6 人贊了文章
如影隨形
如影隨形指的是好像影子老是跟著身體。比喻兩個事物關係密切或兩個人關係密切不能分離。出自先秦·管仲《管子·任法》。
設計模式與我們生活的現實世界就是這種如影隨形的關係
軟體危機
那在說這個關係之前呢,我們先從軟體設計及開發方面開始說起,20世紀50年代爆發了「軟體危機」,面向對象方法也正是在這種情況下誕生的,後來經過大神們的抽象總結,面向對象方法對解決問題的整體思維進行了人性化的革新。
設計模式
那設計模式正是建立在面向對象強大思維的基礎上被「發現」的,為什麼強調是被發現的呢,因為設計模式並不是被發明的。
設計模式的由來
- 1970年,Christopher Alexander建築師提出設計模式概念。
- 1987年,一些設計模式的論文和文章出現了 。
- 1995年,GOF [四人幫]發表了書:《設計模式-可復用面向對象軟體的基礎》(Design Patterns: Elements of Reusable Object-Oriented Software )
現實世界的設計原則及設計模式
上面簡單的介紹了一下設計模式的由來,接下來就回歸我們現實世界。先從設計原則、內聚及耦合說起
設計原則
首先在軟體設計領域,還有很多軟體設計原則,例如開閉原則,對擴展開放,對修改關閉,原則描述言簡意賅,如果映射到現實世界,我們如何連接呢?打個簡單的比方,現在很多互聯網公司上班不需要打卡,有需要打卡的也是彈性的,如彈性上班的考勤而言,彈性上班雖然規定了每天工作要滿8小時,但是沒規定幾點來幾點走,那可以簡單理解成,對於上班考勤這個事,對每天工作滿8小時的修改是關閉的,當然,有膽量的話,你也可以直接和老闆說:「老闆,我想每天工作滿6個小時就想下班」。如果我們是繼承的話,對於工作滿8小時這個方法,它是final修飾的,開放給子類,能看到,但是並不能重寫:)。對於幾點上班,幾點下班,這個是一個介面,是開放的,自己來實現(但是記得要滿8小時喲,因為會有校驗/:壞笑)。那這個就可以理解成一個現實生活對開閉原則的一個映射。這樣的例子還有很多^_^
而符合開閉原則有很多實現方案,包括遵循依賴倒置、合成復用原則等。當然對於繼承來說,也是一個提高擴展性的方案,只不過還要看具體的業務場景,而里氏替換原則又對繼承等(如方法重載)形成約束。它們的關係很有趣。
內聚及耦合
在內聚及耦合的判斷標準上,也是分很多級別的,所以一直存在高低之分,如高內聚、低耦合。這裡面就不展開詳細闡述了。有興趣的小夥伴們可以查一下內聚、耦合的分類。
內聚
內聚這個詞語是從化學中分子間的作用力引申而來,分子間作用力強則表現為內聚程度高,那在軟體設計中,內聚程度的高低,就做為了評比軟體設計好不好的標準,就內聚而言打個比方,例如一個非常小型的創業公司初期,就3個人。人少事多還非常雜,那麼他們的職責肯定不能是專一的。隨著公司發展拿錢融資,規模和員工數量開始增加,事情也多了,這個時候就需要專一職能的員工了,更需要專業化的分工來提高效率,崗位職責清晰。於是,內聚性提高了很多,所以單一職責原則是提高內聚的有效手段。
耦合
一句話理解,活字印刷其實就是一個很好的降低耦合的例子。還有樓宇設計的空調開關,一棟寫字樓,如果空調開關設計成要麼整棟樓都開,要麼整棟樓都關的話。如果單位只在某一層,周六日加班的話,那就幸福了,可能空調費都貴到老闆不想讓你來加班,這正是一個高耦合的例子,繼續思考,那這個開關做到什麼粒度合適呢?那依賴倒置原則、合成復用原則、迪米特法則正式為了解耦而來,耦合度越低,就越有利於復用。
權衡有度
但是凡事都有個度,設計原則及設計模式也是要根據實際的業務場景、業務及項目的要求,包括項目的時間、成本、範圍、質量、資源、風險等因素反覆權衡。如圖:
正如三國殺裡面的英雄一樣,人無完人。
一個軟體系統也不可能全部遵守所有的設計原則到100%這個程度。
所以說,學習設計原則、設計模式之後,對業務模型的抽象能力尤為重要,並且要根據實際的業務場景、當時面臨的各種困難,來決定如何設計及使用。那這個過程需要我們不斷積累、不斷思考、總結經驗教訓,適當做項目復盤,循序漸進,在一些知識點位,溫故而知新,螺旋式上升提高自己的這部分能力。當然這裡面還要有對業務的前瞻性和預期發展方向評估的能力(主要考慮軟體系統的擴展性),但是也不能評估時間太遠,評估10年之後的業務發展可能的模型是沒有必要的。
通過不斷的積累總結,慢慢地自然能練就如何把業務場景及業務模型應用到我們的代碼層面了。在設計模式和現實世界中可以遊刃有餘:)。
設計模式回歸現實生活
設計模式在生活中的例子就更多了
玩電腦
例如攢了一台性能吊炸天的電腦,你不需要去打開主板、打開cpu、打開內存、打開硬碟、打開...只要按一個開關機按鈕即可,這就是外觀模式(別名門面模式)生活中的應用。
裝家電,電子設備充電
例如買了家電,裝修工人不管你要裝什麼電器,兩項、三項的插頭都裝好了,介面做好了。電器出廠的時候也是有統一標準的,實現這個介面,買回來就可以用啦,這就是依賴倒置原則在生活中的應用。繼續來說用電情況,國內標準民用是交流電220V電壓即AC220V,筆記本和手機的充電器裡面會有變壓器,把交流電220V轉換成直流電5V,否則筆記本和手機直接就掛了..必須轉換。而這個又是適配器模式在生活中的應用。
買煎餅
例如有時候上班晚了,在單位樓下買煎餅,去單位茶水間吃早餐。邊吃邊思考...emmm....對於買賣煎餅這件事,一般呢加一個蛋,也有加兩個蛋,也有土豪加十個蛋;再加一些蔬菜、烤腸之類的,把這個簡單的生活場景抽象到業務模型變成了,UML如圖,
那對於這種設計,首先是Battercake煎餅這個類做為父類。BattercakeWithEgg做為加了一個雞蛋的煎餅呢,繼承了Battercake煎餅類。BattercakeWithEggSausage加了一個雞蛋,一根烤腸的煎餅呢又繼承了BattercakeWithEgg帶一個雞蛋的煎餅類,cost方法調用父類的super.cost來增加金額。這種設計可否滿足大眾不同的口味擴展呢,當然是不能的,如果土豪來買帶有十個雞蛋的煎餅,我們還要創建一個類,名字為BattercakeWithTenEgg(暫不考慮英文複數)。 那我們這個程序設計的擴展性就比較差了,大眾口味萬千,煎餅子類爆炸。後期根本不可控。
裝飾者模式
而通過設計模式的裝飾者呢?我們先看一下UML
ABattercake aBattercake;aBattercake = new Battercake();aBattercake = new EggDecorator(aBattercake);aBattercake = new EggDecorator(aBattercake);aBattercake = new SausageDecorator(aBattercake);System.out.println(aBattercake.getDesc()+" 銷售價格:"+aBattercake.cost());
通過裝飾者的封裝大大提高做各種style煎餅的擴展性。那這是生活中設計模式一個簡單的例子。
JDK源碼
那在JDK源碼及開源框架層面,如圖
開源框架源碼
這個圖就表達了,mybatis框架當中關於cache里的裝飾者模式和建造者模式結合的使用。換個視角,來看開源框架源碼,有趣許多。
共享辭彙
最後還想表達一下共享辭彙在日常學習工作中的威力,我們在和同事交流的時候,不可能去很詳細的描述說這個場景我用什麼類繼承了什麼類,然後用什麼類實現了什麼介面,在另外一個類裡面又組合了這個介面,這麼說估計說一半的話估計就要被打斷,我們直接上小黑板畫UML吧,嘿嘿,如果你說在A的抽象類和B的介面之間,通過橋接模式讓他們這兩塊可以獨立擴展。ok,表達的清晰加愉快,省去好多時間。作為工程師一定要表現出工程師professional的一面:)。
嘗試抽象
還有就是可以嘗試去抽象一下生活中的事物,例如,買煎餅、辦理不同銀行的不同種類銀行卡(橋接模式的應用)等等,但是也別走火入魔,看到什麼都想抽象...最簡單的方式:「網購買個鞭子,然後去動物園,找到一頭大象,然後開始抽象」O(∩_∩)O哈哈~。
共勉
合抱之木,生於毫末;九層之台,起於累土;千里之行,始於足下。共勉!
作者:Geely
鏈接:https://www.imooc.com/article/68090來源:慕課網
推薦閱讀:
如何確定自己是否適合做程序員?
半路學編程,可以成為大牛嗎?
如何使用 GitHub?
在做程序員的道路上,你掌握了什麼概念或技術使你感覺自我提升突飛猛進?
你看過/寫過哪些有意思的代碼?
如何在程序里留下彩蛋?
為什麼部分程序員下班後只關顯示器不關電腦?
有哪些好笑的關於程序員的笑話?
推薦閱讀:
※創建型模式之原型模式
※《遊戲設計模式》(遊戲編程模式)全書筆記+Unity實現
※IO完成埠(IOCP)
※Spring框架中的設計模式(五)
※結構型模式之橋接模式