tft每日頭條

 > 生活

 > 高内聚低耦合公式

高内聚低耦合公式

生活 更新时间:2024-12-05 04:46:17

如果這是第二次看到我的文章,歡迎訂閱z哥的公号(跨界架構師)哦~

本文長度為2871字,建議閱讀8分鐘。

堅持原創,每一篇都是用心之作~

下面的這個場景你可能會覺得很熟悉(Z哥我又要出演了):

Z哥:@All 兄弟姐妹們,這次我這邊有個需求需要給「商品上架」增加一道審核,會影響到大家和我交互的接口。大家抽空配合改一下,明天一起更新個版本。小Y:哥,我這幾天很忙啊,昨天剛配合老王改過促銷!小X:行~當一切已成習慣。

作為被通知人,如果在你的現實工作中也發生了類似事件,我相信哪怕嘴上不說,心裡也會有不少想法和抱怨:“md,改的是你,我也要發布,好冤啊!”。

這個問題的根本原因就是多個項目之間的耦合度過于嚴重。

越大型的項目越容易陷入到這個昭潭中,難以自拔。

而解決問題的方式就是進行更合理的分層,并且持續保證分層的合理性。

一提到分層,必然離不開6個字「高内聚」和「低耦合」。

什麼是高内聚低耦合

在z哥之前的文章中有多次提到,分布式系統的本質就是「分治」和「冗餘」

其中,分治就是“分解 -> 治理 -> 歸并”的三部曲。「高内聚」、「低耦合」的概念就來源于此。

高内聚低耦合公式(帶你從入門到精通)1

需要注意的是,當你在做「分解」這個操作的時候,務必要關注每一次的「分解」是否滿足一個最重要的條件:不同分支上的子問題,不能相互依賴,需要各自獨立

因為一旦包含了依賴關系,子問題和父問題之間就失去了可以被「歸并」的意義。

比如,一個「問題Z」被分解成了兩個子問題,「子問題A」和「子問題B」。但是,解問題A依賴于問題B的答案,解問題B又依賴于問題A的答案。這不就等于沒有分解嗎?

題外話:這裡的“如何更合理的分解問題”這個思路也可以用到你的生活和工作中的任何問題上。

所以,當你在做「分解」的時候,需要有一些很好的着力點去切入。

這個着力點就是前面提到的「耦合度」和「内聚度」,兩者是一個此消彼長的關系。

越符合高内聚低耦合這個标準,程序的維護成本就越低。為什麼呢?因為依賴越小,各自的變更對其他關聯方的影響就越小。

所以,「高内聚」和「低耦合」是我們應當持續不斷追求的目标。

題外話:耦合度,指的是軟件模塊之間相互依賴的程度。比如,每次調用方法 A 之後都需要同步調用方法 B,那麼此時方法 A 和 B 間的耦合度是高的。内聚度,指的是模塊内的元素具有的共同點的相似程度。比如,一個類中的多個方法有很多的共同之處,都是做支付相關的處理,那麼這個類的内聚度是高的。二、怎麼做好高内聚低耦合

做好高内聚低耦合,思路也很簡單:定職責、做歸類、劃邊界

首先,定職責就是定義每一個子系統、每一個模塊、甚至每一個class和每一個function的職責。

比如,在子系統或者模塊層面可以這樣。

高内聚低耦合公式(帶你從入門到精通)2

又比如,在class或者function層面可以這樣。

高内聚低耦合公式(帶你從入門到精通)3

我想這點大家平時都會有意識的去做。

做好了職責定義後,内聚性就會有很大的提升,同時也提高了代碼/程序的複用程度。

至此,我們才談得上「單一職責(SRP)」這種設計原則的運用。

其次,做歸類。梳理不同模塊之間的依賴關系。

像上面提到的案例1可以歸類為3層:

  1. 基礎層:商品基礎服務、會員基礎服務、促銷基礎服務
  2. 聚合層:購物車服務、商品詳情服務、登陸服務
  3. 接入層:快閃店API、綜合商城API

高内聚低耦合公式(帶你從入門到精通)4

案例2也可以歸類為3層:

  1. 數據訪問層:訪問會員表數據、訪問會員積分表數據、訪問會員等級表數據
  2. 業務邏輯層:會員登陸邏輯、會員使用積分邏輯、會員升級邏輯
  3. 應用層:接收用戶輸入的賬戶密碼、接收用戶輸入的使用積分數、接收用戶的付款信息

高内聚低耦合公式(帶你從入門到精通)5

最後就是劃邊界。好不容易梳理清楚,為了避免輕易被再次破壞,所以需要設立好合理清晰的邊界。

否則你想的是這樣整齊。

高内聚低耦合公式(帶你從入門到精通)6

實際會慢慢變成這樣混亂。

高内聚低耦合公式(帶你從入門到精通)7

那麼應該怎麼劃邊界呢?

class和function級别。這個層面可以通過codereview或者靜态代碼檢測工具來進行,可以關注的點比如:

  1. 調用某些class必須通過interface而不是implement
  2. 訪問會員表數據的class中不能存在訪問商品數據的function

模塊級别。可以選擇以下方案:

  1. 給每一種類型的class分配不同project,打包到各自的dll(jar)中
  2. 每次代碼push上來的時候檢測其中的依賴是否有超出規定的依賴。例如,不能逆向依賴(檢測dal是否包含bll);不能在基礎層做聚合業務(檢測商品基礎服務是否包含其他基礎服務的dll(jar))。

系統級别。及時識别子系統之間的調用是否符合預期,可以通過接入一個調用鍊跟蹤系統(如,zipkin)來分析請求鍊路是否合法。

讓邊界更清晰、穩定的最佳實踐

很多時候不同的模塊或者子系統會被分配到不同的小組中負責,所以z哥再分享幾個最佳實踐給你。它可以讓系統之間的溝通更穩定。

首先是:模塊對外暴露的接口部分,數據類型的選擇上盡量做到寬進嚴出。比如,使用long代替byte之類的數據類型;使用弱類型代替強類型等等。

舉個「寬進嚴出」的例子:

//使用long代替byte之類的數據類型。void Add(long param1, long param2){ if(param1 <1000&& param2 < 1000){ //先接收進來,到裡面再做邏輯校驗。 //do something... } else{ //do something... }}

其次是:寫操作接口,接收參數盡可能少;讀操作接口,返回參數盡可能多

為什麼呢?因為很多時候,寫操作的背後會存在一個潛在預期,是「準确」。

準确度和可信度有着很大的聯系,隻有更多的邏輯處理在自己掌控範圍内進行才能越具備「可信度」(當然是職責範圍内的邏輯,而不是讓商品服務去計算促銷的邏輯)。反之,上遊系統一個bug就會牽連到你的系統中。

而讀操作背後的潛在預期是:「滿足」。你得提供給我滿足我當前需要的數據,否則我的工作無法開展。

但是呢,在不同時期,客戶端所需要的數據可能會發生變化,你無法預測。所以呢,不要吝啬,返回參數盡可能多,用哪些,用不用是客戶端的事。

還可以做的更好的一些,就是,在可以滿足的基礎上支持按需獲取。客戶端需要返回哪些字段自己通過參數傳過來,如此一來還能避免浪費資源做無用的數據傳輸。

題外話:對外露出的接口設計,可以使用http json 這種跨平台 弱類型的技術組合,可具備更好的靈活性。

實際上,一個程序大多數情況下,在某些時刻是客戶端,又在某些時刻是服務端。站在一個完整程序的角度來提煉參數設計的思路就是:“吃”的要少,“産出”的要多

題外話:有一些設計原則可以擴展閱讀一下。單一職責原則SRP(Single Responsibility Principle)開放封閉原則OCP(Open-Close Principle)裡式替換原則LSP(the Liskov Substitution Principle LSP)依賴倒置原則DIP(the Dependency Inversion Principle DIP)接口分離原則ISP(the Interface Segregation Principle ISP)總結

本文z哥帶你梳理了一下「高内聚低耦合」的本質(來自于哪,意義是什麼),并且分享了一些該怎麼做的思路。

可以看到「高内聚」、「低耦合」其實沒有這個名字那麼高端。哪怕你現在正在工作的項目是一個單體應用,也可以在class和function的設計中體會到「高内聚」、「低耦合」的奧妙。

來來來,接下去馬上開始在項目中「刻意練習」起來吧~


「易伸縮」篇的相關文章:

  • 分布式系統伸縮性大招之——「無狀态」

如果你喜歡這篇文章,可以點一下右下角的「」。

這樣可以給我一點反饋。: )

謝謝你的舉手之勞。


▶ 關于作者:張帆(Zachary)。堅持原創,每一篇都是用心之作

既然都看到這了,順手分享給更多志同道合的小夥伴吧~,歡迎訂閱z哥的公号(跨界架構師)。

定期發表原創内容:架構設計丨分布式系統丨産品丨運營丨一些深度思考

作者:跨界架構師(Zachary)。

更多原創精品,歡迎加入小圈子,請戳【了解更多】

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved