先記住:高內聚是一起變,低耦合是合作靠小介面。
需要深入時:再畫依賴圖。
假設購物車被拆開了,但優惠模組直接修改商品 store
商品模組又監聽優惠 store,摘要元件還會在 render 時補總額。
現在檔案很短,資料流卻像繞了一個圓。
耦合不只發生在 import。共享可變狀態、隱含執行順序、對別人內部欄位的依賴,都會讓模組互相拉扯。
優惠資格與優惠展示規則經常一起改,可以放在同一個功能模組。
按鈕顏色與後端錯誤格式通常不會一起改,就不必交給同一個元件處理。
低耦合則是讓模組透過小而明確的介面合作。
商品列發出 quantityChanged 意圖,流程層決定更新草稿與使報價失效。
商品列不必知道優惠如何重新計算。
不用要求每個事件都經過五層轉送。
若只有父子元件使用,props 與事件通常足夠;更複雜的跨流程協調才需要別的機制。
把元件所有內容搬到 useCart,並不保證架構變好。
如果 useCart 同時處理路由、付款、追蹤、storage 和優惠,仍然有很多變更原因。
我會讓每個抽取單位有一句責任說明。
例如「管理購物車草稿及版本」,比「所有購物車相關東西」清楚。
它需要的依賴應明確傳入或在約定邊界取得,避免偷偷讀全域狀態。
一個簡單的檢查是:測試純金額展示,是否被迫 mock 登入和路由?
如果是,可能有不必要的依賴混進來。
教學案例可以這樣分:
CartItem 顯示商品與發出數量意圖
CouponInput 管輸入
CartFlow 協調版本、驗證與提交
QuoteAdapter 轉換外部資料
摘要只讀取目前有效報價,不再自己重新拼總額。
這會犧牲一點「哪裡都能改資料」的方便,換來清楚的更新入口。
若摘要需要估算,也要明確標為估算值,不能覆蓋伺服器確認的成交資訊。
請檢查購物車模組的 import、共享狀態與隱含順序依賴,畫成文字責任清單。找出哪些變動會迫使不相關模組一起改。優先讓 UI 發出意圖、流程層協調、外部資料在 Adapter 轉換。不要只依檔案行數拆分,也不要把所有邏輯搬進單一 useCart。
這段把高內聚、低耦合轉成具體審查:相同變更原因是否集中、更新入口是否清楚、外部細節是否擴散。
哇,我覺得有時候開發到後面,發現真的沒有更輕鬆。
真的是一個問題一個坑的感覺,不過就順勢繼續讀下去了。
挑一個 hook 或 composable,盡量用一句話描述責任。
如果必須連續使用很多個「以及」,試著找出是否混入不同的變更原因。
再來看看 Adapter 與 Strategy 何時能解決這些問題,何時又只是多一層包裝。