84669 人學習
152542 人學習
20005 人學習
5487 人學習
7821 人學習
359900 人學習
3350 人學習
180660 人學習
48569 人學習
18603 人學習
40936 人學習
1549 人學習
1183 人學習
32909 人學習
闭关修行中......
不要一棒把「耦合」削死。 耦合是一個廣泛的概念。兩個程式模組有關聯就叫做耦合。
某些模組必然要關聯起來才能運作,這是由業務邏輯決定的,不能否認。所以解耦不是字面上的把關聯拆掉,而是把模組之間的關聯放鬆到必要的程度。一些建議:
軟體工程有一條鐵律「高內聚、低耦合」就是這個道理:必要的耦合不可否認,沒有耦合程式就做不成事;但是不必要的緊密耦合,就會讓程式“牽一發而動全身”,最終讓程式設計師的編寫和維護都無從下手。
人類同一時間只能專注於一小部分的內容。 「高內聚、低耦合」就是為了滿足人類的這個特徵——小尺度上只專注於一個模組,局部的編碼工作才能夠進行。大尺度上把具體程式碼轉化為一些抽象的“模組”和“依賴關係”,才能夠抓大放異彩小,把握住程式的脈絡,拼合出一個完整的產品。
想像一下「社會大分工」這個模型-每一個小單位只專注自己的業務部分,與其他單位只存在業務外包的關聯,以及物質、資訊的交互作用。事實證明:這樣的模型比以前大國企「大包大攬」自辦各種職能部門的效率,有量級程度的提升。這就是「高內聚、低耦合」在現實世界中的體現。
程式就是人類創造的第二世界,程式的邏輯無非是世界運作規律的抽象。 跳出程序看程序,就會發現不一樣的觀點和角度。
我也來通俗地講一講,說的不好請勿噴。
簡單概括:耦合就是程式中的一部分跟其他部分之間的關係。解耦合就是把必要的耦合理順,同時盡量減少不必要的耦合(這句話其實就是高內聚低耦合的通俗解釋)。
如何看待耦合取決於你是從什麼視角和層次看待一個程式。如果你正在關注的是一個函數或一個類別的內部實現,這個粒度就很細。這時候你關注的可能是如何把函數/類別寫的漂亮,讓它在功能正確的同時又容易理解。你可以透過改善程式碼的排版、最佳化演算法、將重複的操作封裝為一個新的函數、給變數或函數取更有意義的名字等方法來改善它。
這些方法可以說都跟「高內聚低耦合」有關係。改善程式碼排版:讓程式碼更有程式碼的樣子,讓人更容易看清每句程式碼的作用和意圖。適合的名字:如果你給變數取個名字叫variable,從語意上講它可以儲存任意的值,它的模稜兩可的名字讓人難以分清它和其他程式碼的關係(與其他部分有了不必要的耦合),這就會讓閱讀程式碼的人茫然不知所措。讓變數名字更有意義其實是高內聚的一種體現,即這個變數你是想讓它幹嘛的,別人一眼就能看出來。提取函數就更不用說了。
如果你正在設計一個模組,你關注的可能是模組中的類別和對象,也就是如何讓模組中的類別和物件之間的關係更加簡單和清楚。四人幫的《設計模式》這本書主要就是講這個的,其中的每一個模式都是想辦法降低類別和物件之間的耦合性。
那如果你正在設計一個系統呢,你可能就不關心其中的類了(至少一開始不應該關心),你應該將精力集中到這個系統可以分成幾個模組、各個模組怎麼組合到一起(術語稱為「協作」)構成整個系統等問題上。如果你設計的模組還要去關注其他模組的實作細節,那你的系統就太失敗了。
所以,不管你的角度如何,關注的層次高低,降低複雜度都是必要的。這就是耦合和解耦合的核心理念。
據說任何比喻都是蹩腳的,但我還是想舉一個現實中極其高效與低耦合的例子,那就是軍隊。一個國家的軍隊少則數萬人,多則數百萬人,這麼龐大的一個系統,它的效率卻是驚人的高。為什麼?簡單來說這要歸功於它的幾個行事原則:
紀律嚴明,令行禁止 上級下達指令後不會找不到人執行,或找到人卻不願意做的尷尬狀況(很內聚有木有)
指令不跨級 除非特殊情況,否則命令都是透過直接上級傳達的,司令很少會單獨找小兵做事(每一級在上一級看來都高內聚的,同時連長、班長、團長這些頭頭充當了本級的一個接口,上一級僅透過接口來向下級發命令) 有人說,如果司令直接找小兵給他做事不是比一級一級傳達效率更高嗎? no!為什麼?原因有幾條(注意看,都能跟我們程式設計時的道理連結上,所以說萬物都是想通的)
司令發出的命令通常都是很大的任務,往往要跨越很多部隊甚至兵種,如果讓司令一個一個通知不是要累死? (高層抽像不應該直接與底層實現耦合)
如果允許任意的跨級下達命令,那就很有可能導致多個上級同時給一個士兵下達不同的命令,那這個士兵不是要累死? (導致系統狀態不一致、或分散式系統的忙閒不一等情況)
士兵與直接上級之間的溝通通常是無障礙的,但跨級就難說了。哪個士兵擅長做什麼事只有他的直接上級最清楚,跨級下達命令時可能會導致任務完成效率下降、甚至任務無法完成的後果(高層抽象往往難以駕馭底層細節,進而導致使用不當甚至誤用)
職能分割明確 部隊會依地域、時域、部門、兵種等來劃分整個部隊的職責,這樣一層一層、一塊一塊地把整個部隊分成職責明確的一個個小部分,各個部分相對獨立又是一個有機整體,因此想不高效都很難啊。
你正乘坐直升機遊覽科羅拉多大峽谷,駕駛員——他顯然犯了一個錯誤,在吃魚,他的午餐——突然呻吟起來,暈了過去。幸運的是,他把你留在了離地面100英尺的地方。你推斷,升降桿控制總升力,所以輕輕壓低可以讓直升機平緩降向地面。然而,當你這樣做時,卻發現生活並非那麼簡單。直升機的鼻子向下,開始向左盤旋下降。突然間你發現,你駕駛的這個系統,所有的控制輸入都有次要效應。壓低左手的操作桿,你需要補償性地向後移動右手柄,並踩右踏板。但這些改變中的每一項都會再次影響所有其他的控制。突然間,你在用一個令人難以置信的複雜系統玩雜耍,其中每一項改變都會影響所有其他的輸入。你的工作負擔異常巨大:你的手腳不停地移動,試圖平衡所有互動影響的力量。
——《程式設計師的修行之道》 我認為所有程式設計師都應該看,而且每年都應該重新看一遍的書
耦合性就是不必要的依賴關係,它的存在使得程式碼重複使用變得困難。例如:
一個叫OrderService 的類別負責處理訂單,調用它的createOrder() 方法會在創建訂單的同時發送短信給顧客,那麼這種耦合就導致,當我想創建一個訂單但不想發送短信的時候,我找不到可以重複使用的程式碼,除非將發送簡訊的邏輯從createOrder() 中移除。
OrderService
例如前端html頁面在某個p上寫onclick=foo(),就是耦合。 寫$("#id").click= xxx ,就是解耦合。
我想提問者的困惑不在於找不到答案,而是答案太專業,不夠通俗易懂,以上回答其實太「專業」了。 軟體中的概念往往有其在硬體中的對應,而硬體更形象化,更通俗易懂。 如果你有做電學實驗的經歷,這個概念就太好解釋了。兩塊電路板之間的接線就是耦合,接線越多,電路越複雜,以至於連電路設計者自己都被繞蒙了。一旦發現錯誤,頭緒太多很難理清,也就是所謂維護性變差。想往電路裡接入更多板子難度也會加大,也就是所謂擴展性變差。就算勉強把電路跑通了,同樣的接線方法也很難在其他電路中複製,也就是所謂復用性差。這就是高耦合的壞處。 儘管耦合有種種壞處,但又不可避免,因為沒有耦合電路就跑不起來。怎麼辦呢?有個解決方法就是把耦合性盡可能藏起來。一塊晶片內部電路極為複雜,但是對於外界來說它的內部電路無關緊要。這種把耦合性盡可能藏起來的做法就叫解耦,對內部而言就是高內聚,對外界而言就是低耦合。邏輯效果上就是進行了一層抽象。使得外部可以把晶片視為一個整體,只需要關心它有哪些接口,而這些接口,實際上也是耦合,只不過已經是最小化的耦合了。 有了這樣一層抽象化之後,工程師就可以不關心具體的電路實現,玩純粹的邏輯。這就催生了程式語言。所以程式語言本身已經是在底層硬體解耦的基礎上所做的高度抽象化了。而軟體工程中提到的狹義上的解耦,是指在程式語言(確切的說是用程式語言編制的程式)基礎上進行更高層次的解耦,從而獲得更高層次的抽象。這樣一層層解耦抽像上去,包括作業系統和應用軟體在內的整個軟體大廈就建造出來了。但追根溯源,耦合與解耦概念的起源還是在硬體層次上,而軟體本身其實就是經過解耦的硬體基礎上的抽象。 另外解耦是一個過程,在軟體工程中體現為以高內聚低耦合為原則對程式碼進行重構。 希望我的回答對你理解耦合與解耦的概念會有所幫助。
耦合嘛,又不是苟合,寫那麼多文字也看到不喜歡。上碼:
func foo(){ bar() }
func bar(){ }
foo用到了bar函數,因此,foo依賴bar。 foo耦合了bar。
如果bar是另一個包,那麼在使用前,需要import,這樣我們說foo也依賴bar的包。
說”耦合性就是不必要的依賴關係”,你太緊張了。
因為耦合聽起來口味重。例如變壓器一端的電流,經過“耦合”,在另一端引發電流————無直接電路連接的情況下——多酷。當年計算機科學就是物理學的一個分支,這樣的新貨,得有一個舊酒瓶裝著。
耦合好理解。擴展為 內容耦合,全域耦合,耦合,blabla 就不好了解了。說一堆不給案例,更好複雜。
試著換成依賴好很多。其實http://zh.wikipedia.org/wiki/%E8%80%A6%E5%90%88%E6%80%A7_(%E8%A8%88%E7%AE%97%E6%A9%9F %E7%A7%91%E5%AD%B8) 提到的前三個都是全域變數(資源)依賴。
做資料庫app的。天天見。
關聯式資料庫就是外部耦合。也是全域變數的延伸。寫了很多年的cs應用,不用ORM的,你改改字段名試試就知道苟合——不,強耦合關係——的痛苦了。
這裡的字段就是bar,我的app就是foo。 耦合理論,研究的就是,我對bar改!改!改,卻不需要foo跟著改!改!改。越是如此,就越是低耦合。
這方面做的好的是win32 api。這些年的版本改改,你的win32 app卻不需要改改改,就可以自然升級。牛。
相對獨立,方便單元測試,以此為參考
不要一棒把「耦合」削死。 耦合是一個廣泛的概念。兩個程式模組有關聯就叫做耦合。
某些模組必然要關聯起來才能運作,這是由業務邏輯決定的,不能否認。所以解耦不是字面上的把關聯拆掉,而是把模組之間的關聯放鬆到必要的程度。一些建議:
軟體工程有一條鐵律「高內聚、低耦合」就是這個道理:必要的耦合不可否認,沒有耦合程式就做不成事;但是不必要的緊密耦合,就會讓程式“牽一發而動全身”,最終讓程式設計師的編寫和維護都無從下手。
人類同一時間只能專注於一小部分的內容。 「高內聚、低耦合」就是為了滿足人類的這個特徵——小尺度上只專注於一個模組,局部的編碼工作才能夠進行。大尺度上把具體程式碼轉化為一些抽象的“模組”和“依賴關係”,才能夠抓大放異彩小,把握住程式的脈絡,拼合出一個完整的產品。
想像一下「社會大分工」這個模型-每一個小單位只專注自己的業務部分,與其他單位只存在業務外包的關聯,以及物質、資訊的交互作用。事實證明:這樣的模型比以前大國企「大包大攬」自辦各種職能部門的效率,有量級程度的提升。這就是「高內聚、低耦合」在現實世界中的體現。
程式就是人類創造的第二世界,程式的邏輯無非是世界運作規律的抽象。 跳出程序看程序,就會發現不一樣的觀點和角度。
我也來通俗地講一講,說的不好請勿噴。
簡單概括:耦合就是程式中的一部分跟其他部分之間的關係。解耦合就是把必要的耦合理順,同時盡量減少不必要的耦合(這句話其實就是高內聚低耦合的通俗解釋)。
如何看待耦合取決於你是從什麼視角和層次看待一個程式。如果你正在關注的是一個函數或一個類別的內部實現,這個粒度就很細。這時候你關注的可能是如何把函數/類別寫的漂亮,讓它在功能正確的同時又容易理解。你可以透過改善程式碼的排版、最佳化演算法、將重複的操作封裝為一個新的函數、給變數或函數取更有意義的名字等方法來改善它。
這些方法可以說都跟「高內聚低耦合」有關係。改善程式碼排版:讓程式碼更有程式碼的樣子,讓人更容易看清每句程式碼的作用和意圖。適合的名字:如果你給變數取個名字叫variable,從語意上講它可以儲存任意的值,它的模稜兩可的名字讓人難以分清它和其他程式碼的關係(與其他部分有了不必要的耦合),這就會讓閱讀程式碼的人茫然不知所措。讓變數名字更有意義其實是高內聚的一種體現,即這個變數你是想讓它幹嘛的,別人一眼就能看出來。提取函數就更不用說了。
如果你正在設計一個模組,你關注的可能是模組中的類別和對象,也就是如何讓模組中的類別和物件之間的關係更加簡單和清楚。四人幫的《設計模式》這本書主要就是講這個的,其中的每一個模式都是想辦法降低類別和物件之間的耦合性。
那如果你正在設計一個系統呢,你可能就不關心其中的類了(至少一開始不應該關心),你應該將精力集中到這個系統可以分成幾個模組、各個模組怎麼組合到一起(術語稱為「協作」)構成整個系統等問題上。如果你設計的模組還要去關注其他模組的實作細節,那你的系統就太失敗了。
所以,不管你的角度如何,關注的層次高低,降低複雜度都是必要的。這就是耦合和解耦合的核心理念。
據說任何比喻都是蹩腳的,但我還是想舉一個現實中極其高效與低耦合的例子,那就是軍隊。一個國家的軍隊少則數萬人,多則數百萬人,這麼龐大的一個系統,它的效率卻是驚人的高。為什麼?簡單來說這要歸功於它的幾個行事原則:
紀律嚴明,令行禁止
上級下達指令後不會找不到人執行,或找到人卻不願意做的尷尬狀況(很內聚有木有)
指令不跨級
除非特殊情況,否則命令都是透過直接上級傳達的,司令很少會單獨找小兵做事(每一級在上一級看來都高內聚的,同時連長、班長、團長這些頭頭充當了本級的一個接口,上一級僅透過接口來向下級發命令)
有人說,如果司令直接找小兵給他做事不是比一級一級傳達效率更高嗎? no!為什麼?原因有幾條(注意看,都能跟我們程式設計時的道理連結上,所以說萬物都是想通的)
司令發出的命令通常都是很大的任務,往往要跨越很多部隊甚至兵種,如果讓司令一個一個通知不是要累死? (高層抽像不應該直接與底層實現耦合)
如果允許任意的跨級下達命令,那就很有可能導致多個上級同時給一個士兵下達不同的命令,那這個士兵不是要累死? (導致系統狀態不一致、或分散式系統的忙閒不一等情況)
士兵與直接上級之間的溝通通常是無障礙的,但跨級就難說了。哪個士兵擅長做什麼事只有他的直接上級最清楚,跨級下達命令時可能會導致任務完成效率下降、甚至任務無法完成的後果(高層抽象往往難以駕馭底層細節,進而導致使用不當甚至誤用)
職能分割明確
部隊會依地域、時域、部門、兵種等來劃分整個部隊的職責,這樣一層一層、一塊一塊地把整個部隊分成職責明確的一個個小部分,各個部分相對獨立又是一個有機整體,因此想不高效都很難啊。
——《程式設計師的修行之道》 我認為所有程式設計師都應該看,而且每年都應該重新看一遍的書
耦合性就是不必要的依賴關係,它的存在使得程式碼重複使用變得困難。例如:
一個叫
OrderService
的類別負責處理訂單,調用它的createOrder() 方法會在創建訂單的同時發送短信給顧客,那麼這種耦合就導致,當我想創建一個訂單但不想發送短信的時候,我找不到可以重複使用的程式碼,除非將發送簡訊的邏輯從createOrder() 中移除。例如前端html頁面在某個p上寫onclick=foo(),就是耦合。
寫$("#id").click= xxx ,就是解耦合。
我想提問者的困惑不在於找不到答案,而是答案太專業,不夠通俗易懂,以上回答其實太「專業」了。
軟體中的概念往往有其在硬體中的對應,而硬體更形象化,更通俗易懂。
如果你有做電學實驗的經歷,這個概念就太好解釋了。兩塊電路板之間的接線就是耦合,接線越多,電路越複雜,以至於連電路設計者自己都被繞蒙了。一旦發現錯誤,頭緒太多很難理清,也就是所謂維護性變差。想往電路裡接入更多板子難度也會加大,也就是所謂擴展性變差。就算勉強把電路跑通了,同樣的接線方法也很難在其他電路中複製,也就是所謂復用性差。這就是高耦合的壞處。
儘管耦合有種種壞處,但又不可避免,因為沒有耦合電路就跑不起來。怎麼辦呢?有個解決方法就是把耦合性盡可能藏起來。一塊晶片內部電路極為複雜,但是對於外界來說它的內部電路無關緊要。這種把耦合性盡可能藏起來的做法就叫解耦,對內部而言就是高內聚,對外界而言就是低耦合。邏輯效果上就是進行了一層抽象。使得外部可以把晶片視為一個整體,只需要關心它有哪些接口,而這些接口,實際上也是耦合,只不過已經是最小化的耦合了。
有了這樣一層抽象化之後,工程師就可以不關心具體的電路實現,玩純粹的邏輯。這就催生了程式語言。所以程式語言本身已經是在底層硬體解耦的基礎上所做的高度抽象化了。而軟體工程中提到的狹義上的解耦,是指在程式語言(確切的說是用程式語言編制的程式)基礎上進行更高層次的解耦,從而獲得更高層次的抽象。這樣一層層解耦抽像上去,包括作業系統和應用軟體在內的整個軟體大廈就建造出來了。但追根溯源,耦合與解耦概念的起源還是在硬體層次上,而軟體本身其實就是經過解耦的硬體基礎上的抽象。
另外解耦是一個過程,在軟體工程中體現為以高內聚低耦合為原則對程式碼進行重構。
希望我的回答對你理解耦合與解耦的概念會有所幫助。
耦合嘛,又不是苟合,寫那麼多文字也看到不喜歡。上碼:
1. 何為耦合?
func foo(){
bar()
}
func bar(){
}
foo用到了bar函數,因此,foo依賴bar。 foo耦合了bar。
2. 包依賴
如果bar是另一個包,那麼在使用前,需要import,這樣我們說foo也依賴bar的包。
3. 簡化: 耦合≈依賴
說”耦合性就是不必要的依賴關係”,你太緊張了。
4. 為何不直接說依賴?
因為耦合聽起來口味重。例如變壓器一端的電流,經過“耦合”,在另一端引發電流————無直接電路連接的情況下——多酷。當年計算機科學就是物理學的一個分支,這樣的新貨,得有一個舊酒瓶裝著。
5. 為何耦合難以理解?
耦合好理解。擴展為 內容耦合,全域耦合,耦合,blabla 就不好了解了。說一堆不給案例,更好複雜。
試著換成依賴好很多。其實http://zh.wikipedia.org/wiki/%E8%80%A6%E5%90%88%E6%80%A7_(%E8%A8%88%E7%AE%97%E6%A9%9F %E7%A7%91%E5%AD%B8) 提到的前三個都是全域變數(資源)依賴。
6. 高耦合問題的案例
做資料庫app的。天天見。
關聯式資料庫就是外部耦合。也是全域變數的延伸。寫了很多年的cs應用,不用ORM的,你改改字段名試試就知道苟合——不,強耦合關係——的痛苦了。
這裡的字段就是bar,我的app就是foo。
耦合理論,研究的就是,我對bar改!改!改,卻不需要foo跟著改!改!改。越是如此,就越是低耦合。
7.低耦合的案例
這方面做的好的是win32 api。這些年的版本改改,你的win32 app卻不需要改改改,就可以自然升級。牛。
相對獨立,方便單元測試,以此為參考