這是一對互相拉扯的味道。Message Chains 是層層呼叫如
a.getB().getC().getD(),呼叫端被綁死在物件的內部結構上;解法是隱藏委託或把這段導航抽成函式。但一旦委託藏過頭,某個類別過半函式都只是把呼叫轉手給別人,就變成 Middle Man(不必要的傳話);解法反過來——移除中間人,直接溝通。兩個修法方向相反,拿捏之間才是重點。
🧠 Why It's a Problem
- 訊息鏈的耦合:
a.getB().getC().getD()讓呼叫端知道了一整條導航路徑;只要中間任一層的結構改變,呼叫端就得跟著改。 - 中間人的空轉:本章把味道歸在模組間的耦合——模組間應低耦合,既要避免過度親密,也要避免不必要的傳話。一個類別若過半函式只是委託給另一類別,它就沒帶來價值,只是多一層轉手。
- 兩種過度的方向相反:訊息鏈是「暴露太多」,中間人是「隱藏太多」。它們是同一條光譜的兩端。
NOTE
修法會互相拉扯:對訊息鏈用「隱藏委託」會多加轉手方法,過頭就長出中間人;對中間人「移除中間人」讓呼叫端直接對話,過頭又長回訊息鏈。目標不是站到某一端,而是找到平衡點。
⚖️ Refactoring
訊息鏈 → 隱藏委託(或把導航抽成函式);中間人 → 移除中間人,直接溝通。
Message Chains — 前:一路 get 下去
// 呼叫端被綁在整條結構上:manager 藏在 department 裡,department 藏在 person 裡
const manager = person.getDepartment().getManager();呼叫端得知道 person → department → manager 這條路;department 只是被穿過去的中繼站。
Message Chains — 後:隱藏委託
class Person {
// 讓 Person 代為轉交,呼叫端不再看見 department
getManager() {
return this.department.getManager();
}
}
const manager = person.getManager();呼叫端只跟 person 打交道,中間的結構被藏起來,改變 department 不再波及呼叫端。
Middle Man — 前:過半函式只是轉手
class Person {
// 這些方法本身沒做事,只是把呼叫轉交給 department
getManager() {
return this.department.getManager();
}
getChargeCode() {
return this.department.getChargeCode();
}
}隱藏委託加得太多,Person 淪為只會傳話的中間人。
Middle Man — 後:移除中間人,直接溝通
// 讓呼叫端直接對真正做事的物件說話
const manager = person.department.getManager();拿掉空轉的轉手方法,呼叫端直接與 department 溝通。
TIP
同一組物件,兩個修法把你推向相反方向。判斷依據不是規則,而是:轉手方法有沒有帶來封裝的價值?沒有就是中間人,收掉它;有就留著擋住訊息鏈。
🔑 Takeaways
- Message Chains:
a.getB().getC().getD()把呼叫端綁在物件結構上;解法是隱藏委託或把導航抽成函式。 - Middle Man:一個類別過半函式只是委託轉手,沒帶來價值;解法是移除中間人,直接溝通。
- 兩者是耦合光譜的兩端——一個暴露太多、一個隱藏太多,修法方向相反,要在兩者之間拿捏平衡。
No notes yet — jot your takeaways or Q&A here.