<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Coupling on Tarragon</title><link>https://tarrragon.github.io/blog/tags/coupling/</link><description>Recent content in Coupling on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 19 Oct 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/coupling/index.xml" rel="self" type="application/rss+xml"/><item><title>Coupling（耦合）</title><link>https://tarrragon.github.io/blog/software-design/design-principles/knowledge-cards/coupling/</link><pubDate>Mon, 19 Oct 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/software-design/design-principles/knowledge-cards/coupling/</guid><description>&lt;p>Coupling（耦合）是模組之間互相依賴的程度：一個模組改變時，另一個模組要跟著改的可能性與範圍。這裡的模組泛指任何有對外介面的程式單位：函式、類別、檔案或套件。這個詞與 &lt;a href="https://tarrragon.github.io/blog/software-design/design-principles/knowledge-cards/cohesion/" data-link-title="Cohesion（內聚）" data-link-desc="要判斷一個模組裡的元素放在一起的理由夠不夠強、或讀到「高內聚、低耦合」想知道內聚量的是什麼時：內聚是模組內部元素彼此相關的程度，依放在一起的理由分成由弱到強的幾種">Cohesion（內聚）&lt;/a> 一起由 Larry Constantine 在 1960 年代後期的結構化設計裡提出，1974 年 Stevens、Myers 與 Constantine 的〈Structured Design〉把它們寫成模組設計的兩個衡量標準：內聚量模組內部，耦合量模組之間。低耦合與高內聚常一起出現，原因是它們來自同一個切法：把會一起改的元素放進同一個模組，元素之間的讀寫就留在模組內部，模組之間要交換的資料與呼叫隨之變少。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>耦合依兩個模組共享的內容分成幾種，由強到弱是：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>內容耦合（content）&lt;/strong>：一個模組直接使用另一個模組內部的程式碼或資料，例如跳進對方的內部、改對方的私有欄位。&lt;/li>
&lt;li>&lt;strong>共用耦合（common）&lt;/strong>：好幾個模組存取同一份全域資料。&lt;/li>
&lt;li>&lt;strong>外部耦合（external）&lt;/strong>：模組共用一個外部規定的資料格式、通訊協定或裝置介面。&lt;/li>
&lt;li>&lt;strong>控制耦合（control）&lt;/strong>：一個模組傳一個旗標給另一個模組，由旗標決定接收的模組要走哪一條邏輯。&lt;/li>
&lt;li>&lt;strong>戳記耦合（stamp，其他中文資料也寫作「標記耦合」）&lt;/strong>：模組之間傳遞一整個複合資料結構，而接收的一方只用到其中一部分欄位。&lt;/li>
&lt;li>&lt;strong>資料耦合（data）&lt;/strong>：模組之間只透過參數傳遞需要的資料。&lt;/li>
&lt;/ul>
&lt;p>耦合越強，一個模組的修改越可能要求另一個模組跟著改。&lt;a href="https://tarrragon.github.io/blog/software-design/design-principles/knowledge-cards/open-closed-principle/" data-link-title="Open-Closed Principle（開放封閉原則）" data-link-desc="要在新增一種格式、一種類型或一種規則時不必改動既有程式碼，或要判斷一個擴充點值不值得先做時：模組對選定的那一類變更封閉，靠的是使用端只依賴一個固定的抽象">Open-Closed Principle（開放封閉原則）&lt;/a>用來降低耦合的手段是讓使用端只依賴一個固定的抽象：使用端與各個實作之間只剩下對那個抽象的依賴，實作的內部改變不會傳到使用端。&lt;/p>
&lt;h2 id="可觀察訊號與例子">可觀察訊號與例子&lt;/h2>
&lt;p>耦合過強的訊號，是修改一個模組時發現要同時改另一個模組，而這次修改的需求只跟被修改的那個模組有關：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>改一個模組的內部欄位，另一個模組編譯失敗或行為改變&lt;/strong>：另一個模組直接讀寫了這些欄位，是內容耦合。&lt;/li>
&lt;li>&lt;strong>改一份全域設定，幾個看似無關的模組行為都變了&lt;/strong>：它們共用同一份全域資料，是共用耦合。Martin 對全域變數的說明在 &lt;a href="https://tarrragon.github.io/blog/software-design/design-principles/knowledge-cards/open-closed-principle/" data-link-title="Open-Closed Principle（開放封閉原則）" data-link-desc="要在新增一種格式、一種類型或一種規則時不必改動既有程式碼，或要判斷一個擴充點值不值得先做時：模組對選定的那一類變更封閉，靠的是使用端只依賴一個固定的抽象">Open-Closed Principle&lt;/a> 卡片。&lt;/li>
&lt;li>&lt;strong>函式收一個 &lt;code>mode&lt;/code> 或 &lt;code>is_xxx&lt;/code> 參數，依它切換成完全不同的兩套行為&lt;/strong>：呼叫端在控制被呼叫端的流程，是控制耦合；這種函式通常也代表兩套行為各自有不同的改變理由，拆成兩個函式之後，呼叫端直接呼叫它要的那一個。&lt;/li>
&lt;li>&lt;strong>函式收一整個物件、只讀其中一兩個欄位&lt;/strong>：例如計算運費的函式收整個訂單物件，只讀了寄送地址。訂單物件的結構一改，運費函式就要重新確認，是戳記耦合；測試這個函式時也得先造出一整個訂單物件。改成只收寄送地址，就降成資料耦合。&lt;/li>
&lt;/ul>
&lt;p>兩個模組之間有耦合本身不是錯誤，模組要合作就一定要交換資料或呼叫對方。要確認的是交換的內容是否只有完成這次呼叫實際用到的資料。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>降低耦合的設計責任是讓模組之間只交換合作需要的資料，而且依賴的方向穩定。判斷問句是：改這個模組時，有哪些別的模組要跟著改，原因是什麼；原因是那些模組讀了這個模組的內部、共用了同一份可變資料、或用旗標控制這個模組的流程，就把那份依賴改成更弱的形式，依情形選一種：只傳它實際用到的資料（降成資料耦合），或改成依賴一個抽象（做法見開放封閉原則）。降低耦合之前先確認那兩個模組是否本來就該是同一個：兩者過去的修改幾乎每次都一起發生，或一方大量讀寫另一方的內部資料，拆成兩個模組只會讓每次修改都要改兩處，形成 &lt;a href="https://tarrragon.github.io/blog/software-design/design-principles/knowledge-cards/shotgun-surgery/" data-link-title="Shotgun Surgery（散彈式修改）" data-link-desc="每做一個小變更都要同時改好幾個檔案、漏改一處就出錯，或依行數拆完檔之後同一個主題的修改散到好幾份時：這是同一個改變理由被拆散到多個模組的壞味道">Shotgun Surgery（散彈式修改）&lt;/a>。這時把兩者合併成一個模組比降低它們之間的耦合更合適，合併之後它們放在一起的理由相同，內聚也隨之提高。&lt;/p></description><content:encoded><![CDATA[<p>Coupling（耦合）是模組之間互相依賴的程度：一個模組改變時，另一個模組要跟著改的可能性與範圍。這裡的模組泛指任何有對外介面的程式單位：函式、類別、檔案或套件。這個詞與 <a href="/blog/software-design/design-principles/knowledge-cards/cohesion/" data-link-title="Cohesion（內聚）" data-link-desc="要判斷一個模組裡的元素放在一起的理由夠不夠強、或讀到「高內聚、低耦合」想知道內聚量的是什麼時：內聚是模組內部元素彼此相關的程度，依放在一起的理由分成由弱到強的幾種">Cohesion（內聚）</a> 一起由 Larry Constantine 在 1960 年代後期的結構化設計裡提出，1974 年 Stevens、Myers 與 Constantine 的〈Structured Design〉把它們寫成模組設計的兩個衡量標準：內聚量模組內部，耦合量模組之間。低耦合與高內聚常一起出現，原因是它們來自同一個切法：把會一起改的元素放進同一個模組，元素之間的讀寫就留在模組內部，模組之間要交換的資料與呼叫隨之變少。</p>
<h2 id="概念位置">概念位置</h2>
<p>耦合依兩個模組共享的內容分成幾種，由強到弱是：</p>
<ul>
<li><strong>內容耦合（content）</strong>：一個模組直接使用另一個模組內部的程式碼或資料，例如跳進對方的內部、改對方的私有欄位。</li>
<li><strong>共用耦合（common）</strong>：好幾個模組存取同一份全域資料。</li>
<li><strong>外部耦合（external）</strong>：模組共用一個外部規定的資料格式、通訊協定或裝置介面。</li>
<li><strong>控制耦合（control）</strong>：一個模組傳一個旗標給另一個模組，由旗標決定接收的模組要走哪一條邏輯。</li>
<li><strong>戳記耦合（stamp，其他中文資料也寫作「標記耦合」）</strong>：模組之間傳遞一整個複合資料結構，而接收的一方只用到其中一部分欄位。</li>
<li><strong>資料耦合（data）</strong>：模組之間只透過參數傳遞需要的資料。</li>
</ul>
<p>耦合越強，一個模組的修改越可能要求另一個模組跟著改。<a href="/blog/software-design/design-principles/knowledge-cards/open-closed-principle/" data-link-title="Open-Closed Principle（開放封閉原則）" data-link-desc="要在新增一種格式、一種類型或一種規則時不必改動既有程式碼，或要判斷一個擴充點值不值得先做時：模組對選定的那一類變更封閉，靠的是使用端只依賴一個固定的抽象">Open-Closed Principle（開放封閉原則）</a>用來降低耦合的手段是讓使用端只依賴一個固定的抽象：使用端與各個實作之間只剩下對那個抽象的依賴，實作的內部改變不會傳到使用端。</p>
<h2 id="可觀察訊號與例子">可觀察訊號與例子</h2>
<p>耦合過強的訊號，是修改一個模組時發現要同時改另一個模組，而這次修改的需求只跟被修改的那個模組有關：</p>
<ul>
<li><strong>改一個模組的內部欄位，另一個模組編譯失敗或行為改變</strong>：另一個模組直接讀寫了這些欄位，是內容耦合。</li>
<li><strong>改一份全域設定，幾個看似無關的模組行為都變了</strong>：它們共用同一份全域資料，是共用耦合。Martin 對全域變數的說明在 <a href="/blog/software-design/design-principles/knowledge-cards/open-closed-principle/" data-link-title="Open-Closed Principle（開放封閉原則）" data-link-desc="要在新增一種格式、一種類型或一種規則時不必改動既有程式碼，或要判斷一個擴充點值不值得先做時：模組對選定的那一類變更封閉，靠的是使用端只依賴一個固定的抽象">Open-Closed Principle</a> 卡片。</li>
<li><strong>函式收一個 <code>mode</code> 或 <code>is_xxx</code> 參數，依它切換成完全不同的兩套行為</strong>：呼叫端在控制被呼叫端的流程，是控制耦合；這種函式通常也代表兩套行為各自有不同的改變理由，拆成兩個函式之後，呼叫端直接呼叫它要的那一個。</li>
<li><strong>函式收一整個物件、只讀其中一兩個欄位</strong>：例如計算運費的函式收整個訂單物件，只讀了寄送地址。訂單物件的結構一改，運費函式就要重新確認，是戳記耦合；測試這個函式時也得先造出一整個訂單物件。改成只收寄送地址，就降成資料耦合。</li>
</ul>
<p>兩個模組之間有耦合本身不是錯誤，模組要合作就一定要交換資料或呼叫對方。要確認的是交換的內容是否只有完成這次呼叫實際用到的資料。</p>
<h2 id="設計責任">設計責任</h2>
<p>降低耦合的設計責任是讓模組之間只交換合作需要的資料，而且依賴的方向穩定。判斷問句是：改這個模組時，有哪些別的模組要跟著改，原因是什麼；原因是那些模組讀了這個模組的內部、共用了同一份可變資料、或用旗標控制這個模組的流程，就把那份依賴改成更弱的形式，依情形選一種：只傳它實際用到的資料（降成資料耦合），或改成依賴一個抽象（做法見開放封閉原則）。降低耦合之前先確認那兩個模組是否本來就該是同一個：兩者過去的修改幾乎每次都一起發生，或一方大量讀寫另一方的內部資料，拆成兩個模組只會讓每次修改都要改兩處，形成 <a href="/blog/software-design/design-principles/knowledge-cards/shotgun-surgery/" data-link-title="Shotgun Surgery（散彈式修改）" data-link-desc="每做一個小變更都要同時改好幾個檔案、漏改一處就出錯，或依行數拆完檔之後同一個主題的修改散到好幾份時：這是同一個改變理由被拆散到多個模組的壞味道">Shotgun Surgery（散彈式修改）</a>。這時把兩者合併成一個模組比降低它們之間的耦合更合適，合併之後它們放在一起的理由相同，內聚也隨之提高。</p>
]]></content:encoded></item></channel></rss>