高內聚與低耦合web
WHAT設計模式
"高內聚"與"低耦合"是軟件設計和開發中常常出現的一對概念。它們既是作好設計的途徑,也是評價設計好壞的標準。"高內聚"是說,一個業務應當儘可能把它所涉及的功能和代碼放到一個模塊中;"低耦合"則是說,一個業務應當儘可能減小對其它業務或功能模塊的依賴。併發
「高內聚低耦合」也是這麼成雙成對地出現app
這一對概念其實不只適用於軟件行業。若是你是宅男/宅女,高內聚就是吃喝拉撒睡都不用出門,低耦合就是不用跟人打交道。若是你是上班族,高內聚就是工做都由本身說了算,低耦合就是跨組/跨部門的溝通協做少。若是你常跟政府部門打交道,必定還記得以往去政府辦一個證實要跑八九個部門、蓋十幾個章的麻煩,這其實就是政府服務"低內聚"的惡果——後來政府精簡辦事流程,一個窗口蓋完全部章,這就是一種"高內聚"的服務。若是你是蘋果的重度用戶,必定對"封閉生態環境"體會深入:它當然能提供很好的服務,可是深陷其中以後——iPhone、iPad、macbook、iCloud等——那麼,即便其中某項服務無覺得繼了、或者知足不了需求了,也沒法輕易地脫身而出、改換門庭。這就是"高耦合"帶來的難題。ide
一隻「高內聚低耦合」的喵……
性能
WHY & WHY NOT學習
高內聚低耦合的優勢和缺點都是顯而易見的。測試
優勢優化
若是一個模塊、一個系統可以作到高內聚、低耦合,那麼,它就具備了很是高的可擴展性。可擴展性高意味着「將來有無限可能」:功能不知足新需求了,在模塊內部簡單擴展就能知足;性能上達不到要求了,系統內部挖潛就能達標;技術太過陳舊要更新換代了,本身就能完成新陳代謝……ui
這麼說可能有些費解,咱們仍是舉例子吧。
對宅男/宅女來講,高內聚就是吃喝拉撒睡都不用出門,低耦合就是不用跟人打交道。這樣一來,我想吃披薩就吃披薩,想喝兩碗豆漿就喝兩碗豆漿,徹底不用顧慮別人想吃什麼、別人會說什麼。這樣的生活愜意不?
對上班族來講,高內聚就是工做都由本身說了算,低耦合就是跨組/跨部門的溝通協做少。這樣一來,我想用數據集A就用數據集A,想用數據集B就用數據集B;想用Excel用Excel,想寫腳本寫腳本;想用PPT彙報就用PPT彙報,想用demo彙報就用demo彙報。這樣的工做快樂不?
我反正是……
技術上……我仍是舉個例子吧。咱們系統中有一個模塊,用於處理用戶短信驗證操做。簽約驗證成功後,針對具體的業務還須要作一些後續處理。隨着業務的不斷髮展,後續業務處理從最初的一套邏輯增長到如今的五套邏輯。此外咱們還作了一些技術優化,如優化庫表結構、增長併發處理等,最後的流程大概是這樣的:
短信驗證模塊的基本流程
因爲整個短信驗證模塊、以及後續業務處理模塊都作到了高內聚、低耦合(自吹自擂臉),所以,不管是業務擴展仍是技術優化,都隻影響到了各自對應的模塊,其它模塊、功能對此毫無感知。尤爲是業務擴展、增長一個後續業務處理模塊時,其它後續業務處理模塊絲絕不受影響。沒有影響意味着開發不用改代碼、測試不用迴歸測試、上線時間能夠縮短、老代碼裏不會引入新問題……
可見,高內聚低耦合的設計能帶來多贏的結果。對開發來講,改動的代碼固然是越少越好——高內聚低耦合的設計能減小要修改的代碼量。對測試來講,測試範圍固然是越小越好——高內聚低耦合的模塊只須要測試新增功能而不須要回歸原有功能。對產品來講,需求上線的時間固然是越短越好——高內聚低耦合的設計能減小開發和測試的工做量,上線時間天然也就變短了。對用戶來講,系統問題固然是越少越好——高內聚低耦合的設計至少能保證老代碼正常運行,不會由於新功能而莫名崩潰。
你好了不?
缺點
優勢如此顯而易見,爲何實際工做中不多有人認真執行「高內聚低耦合」的設計要求呢?
若是你是一個政府部門,你是願意本身只蓋一個章、讓用戶去跑其它部門蓋完剩下的十幾個章,仍是願意讓用戶只來你這一個部門、你去跑其它部門改完全部的章?若是你是一家商店,你是願意讓用戶把錢全都花在你的店裏,仍是願意提供一堆服務讓用戶去別的店鋪消費?作軟件設計也要面對「投入產出比」的考慮。若是一個良好設計的成本過高而收益過低、甚至與主要目標背道而馳,那麼人們天然就會用腳投票、不使用這種設計。
前幾年這種漫畫沒少見吧
「高內聚低耦合」的設計就經常會陷入這樣的困境中。首先,要嚴格作到高內聚、低耦合,一般多要付出不少精力來作設計,還經常會增長很多的開發工做量。而這些額外成本有時並不必定能帶來指望的結果。之前面說的短信驗證功能模塊爲例,若是五種業務邏輯的差別都只有一兩行代碼,那麼全用if-else的方式放在一個類中會是一種更合適的方法。可是,若是業務邏輯自己比較複雜、或者彼此之間差別比較大,還用if-else處理的話,最後代碼會變成一團亂麻、快速腐化。所以,儘管咱們的設計多了六個類(一個業務分發類、五個不一樣的業務處理類),並致使了前期開發時多花了一天半天的時間,但整個模塊的可維護性、可擴展性都有很大提升,能夠說是「過當」了吧。
這是短信驗證模塊目前的類圖
其次,「高內聚低耦合」是一種原則性的設計準則。在現實中,原則性的東西通常都會爲靈活性——好比工期啦,歷史遺留問題啦,部門關係啦——讓步。我曾經常常聽到「之前就是這麼作的,此次也這樣處理吧」、「他們的接口就是這樣的,咱們也沒辦法」這樣的話,也常常看到由於這些緣由而放棄更好的設計,甚至所以而再也不思考有沒有更好的設計。有時真讓人感嘆技術其實什麼都改變不了。另外,原則性的東西每每太務虛而沒法落到實處。「這個模塊不夠高內聚」,「這段代碼的耦合度過高了」,具體是怎麼不夠高內聚?要改爲怎樣才能下降耦合度?徹底叫人丈二金剛摸不着頭腦。最後,法學上有種罪名叫作「籮筐罪」,當你以爲一個東西有問題、但又說不清楚具體是什麼問題時,就能夠把它納入「籮筐罪」中——也就是所謂「xx罪是個框,什麼都能往裏裝」。「高內聚低耦合」能夠說是軟件設計界的「籮筐罪」,只要想往裏裝就能往裏裝。例如前面那個短信驗證功能模塊,它真的知足了「高內聚低耦合」了嗎?雖然通過精心設計,可是若是要挑,也還能挑出一籮筐毛病來。因此,「高內聚低耦合」的度很難把握,過於執着甚至可能走火入魔。這也是爲何「高內聚低耦合」不多在實際工做中說起和應用的緣由之一。
原則和實踐……經常就是這麼殘酷
HOW
有些問題能夠靠技術來解決。例如,開發成本高這個問題在團隊開發水平提升到必定層次以後就迎刃而解了;太過務虛的問題也能夠經過學習和掌握SOLID、設計模式等具體的設計技能來解決。這些具體的技術會在之後慢慢討論。可是非技術的問題——例如歷史包袱、部門關係等,我就心有餘而力不足了。
高內聚低耦合與抽象
雖然高內聚低耦合有上面這些問題,可是,在作業務抽象的設計時,咱們仍是要認真考慮、並遵照這個原則。由於高內聚低耦合不只是作好設計的途徑、也是評價設計好壞的標準:對於面向對象的業務抽象設計來講更是如此。
一個好的業務抽象必須能表達出本身「是什麼」或者「能作什麼」、而隱藏本身「怎麼作」。高內聚、低耦合的理念正適合用來讓業務抽象隱藏本身的實現細節。若是一個業務抽象不夠內聚或者過分耦合,它必定會過多地把本身的實現細節泄露出去。還記得在《抽象》一文中出現的QueryService嗎?它把queryFromRemote和queryFromLocal暴露到業務抽象外部,致使了使用接口時的種種不便,這就是不夠高內聚的結果。還有ExcelService,這個接口與2003版的Excel文件格式過分耦合了,結果沒法順利地升級到20007版Excel上。