文章同步於it邦
介紹
今天要介紹依賴反向原則(DIP, Dependency Inversion Principle)
最靈活的系統是『原始碼的依賴關係指涉及抽象不涉及具體』
-Clean Architecture(P.75)
上述這段話的意思就是,我們應該將我的模組依賴於抽象概念
但這段話其實不切實際,特別像是Python這些大量依賴第三方套件的語言
基本上我們要做的功能已經有人幫我們做好了
甚至我們連依賴list.count()
這種都屬於依賴具體物件的方法
這種情況我們不可也不該避免
所以在應用DIP時,我們可以忽略作業系統的穩定背景,我們也可以信任他們不會改變。
要注意的是,系統中容易變化的具體元素。
實作
同樣以php為例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Dog { public function bark() { return "汪!"; } }
class Cat { public function meow() { return "喵~~"; } }
class PetOwner { private $dog; private $cat;
public function __construct() { $this->dog = new Dog(); $this->cat = new Cat(); }
public function playWithPets() { $dogSound = $this->dog->bark(); $catSound = $this->cat->meow(); return "Dog: $dogSound, Cat: $catSound"; } }
|
我們可以看到PetOwner
依賴於Dog
和Cat
假設未來我要多領養幾隻寵物,我就必須一直持續在petOwner
裡面一直新增
持續的對petOwner
做修改
萬一上層的class要做修改,那更改的範圍就會更大
換個方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| interface PetSound { public function makeSound(); }
class Dog implements PetSound { public function makeSound() { return "汪!"; } }
class Cat implements PetSound { public function makeSound() { return "喵~~"; } }
class PetOwner { private $pets = [];
public function addPet(PetSound $pet) { $this->pets[] = $pet; }
public function playWithPets() { $sounds = []; foreach ($this->pets as $pet) { $sounds[] = $pet->makeSound(); } return implode(", ", $sounds); } }
|
在這個例子中,我們引入了一個 PetSound
抽象介面,並讓 Dog
和 Cat
類實現這個介面
PetOwner
類不再直接創建寵物的實例,而是通過 addPet
方法將寵物加入,並且在 playWithPets
方法中調用了抽象介面的方法。
這種做法降低了耦合度,使得我們可以較容易地擴展或修改代碼,而不會影響其他部分。這符合 DIP 原則的理念。
參考資料
Clean Architecture(ch.11)