0%

【Day-10】依賴反向原則(DIP)

文章同步於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依賴於DogCat

假設未來我要多領養幾隻寵物,我就必須一直持續在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 抽象介面,並讓 DogCat 類實現這個介面
PetOwner 類不再直接創建寵物的實例,而是通過 addPet 方法將寵物加入,並且在 playWithPets 方法中調用了抽象介面的方法。

這種做法降低了耦合度,使得我們可以較容易地擴展或修改代碼,而不會影響其他部分。這符合 DIP 原則的理念。

參考資料

Clean Architecture(ch.11)