從字面到本質,用最直白的方式理解依賴倒置原則(Dependency Inversion Principle, DIP):
一、字面拆解:四個字的含義
-
依賴:
- 指代碼中模塊/類之間的使用關係(如A類調用B類的方法)
- 例如:
Service依賴Repository讀寫數據
-
倒置:
- 把傳統的依賴方向"反轉"過來
-
類比:
- 傳統:高層模塊→直接依賴→底層模塊(如Service→MySQL)
- 倒置後:高層模塊→依賴抽象←底層模塊實現
二、直觀比喻
場景:手機充電
-
傳統方式(未倒置):
手機 → 直接依賴 → 特定充電口(如Lightning接口) (如果換成USB-C,必須改手機硬件) -
依賴倒置後:
手機 → 依賴「充電協議」標準 ← USB-C/Lightning實現協議 (只要符合協議,接口可以隨意更換)
三、核心思想
-
面向接口編程:
- 定義抽象協議(接口)
- 具體實現必須遵守協議
-
控制反轉:
- 高層模塊定義規則(接口)
- 底層模塊服從規則(實現接口)
-
解耦:
修改數據庫(如MongoDB→MySQL)時, 業務代碼(Service層)完全不需要改動
四、對比示例
未倒置的代碼:
// 服務層直接依賴具體MySQL實現(危險!)
type UserService struct {
repo *MySQLUserRepository // 直接綁定MySQL
}
倒置後的代碼:
// 1. 先定義抽象(領域層)
type UserRepository interface {
GetUser(id int) (*User, error)
}
// 2. 服務層只依賴抽象
type UserService struct {
repo UserRepository // 可以是MySQL/Mongo/任何實現
}
// 3. 具體實現(基礎設施層)
type MySQLUserRepository struct{}
func (m *MySQLUserRepository) GetUser(id int) (*User, error) {
// 具體MySQL查詢...
}
五、為什麼叫"倒置"?
傳統分層架構:
高層模塊
↓
底層模塊
應用DIP後:
高層模塊
↓
抽象接口 ←─ 底層模塊
依賴方向從自上而下變成了自下而上實現抽象,因此稱為"倒置"。
六、生活案例
未倒置:
你 → 直接依賴 → 某家外賣店的廚師
(如果換餐廳,你要重新適應)
倒置後:
你 → 依賴「送餐標準」 ← 各餐廳實現標準
(只要符合送餐標準,換哪家餐廳你都無需改變)
七、關鍵記憶點
- 高層制定規則(定義接口)
- 底層服從規則(實現接口)
- 改動互不影響(解耦)