依賴反轉原則

Depend on abstractions, not on concretions.
Robert C. Martin

依賴反轉原則,全名 Dependency Inversion Principle,簡稱 DIP

定義

高階模組不應該依賴低階模組,兩者應該要依賴其抽象,抽象不要依賴細節,細節要依賴抽象。
不要把程式碼寫死某種實作上。

秘訣

  • 互動的部分交給抽象類別(abstract class)或介面(interface)
  • 會改變的實作,就放到子類別裡面

提醒

設計階段就可以先以抽象層次的互動來避開這個問題
抽象層次不要太高,以免無法對焦於真正關注的類別特徵

範例

來看個例子。
有一位計程車司機,他開著 Toyota 的車來工作。
但如果有天他換車了,換開 Nissan,原本的 drive function 就不能用了…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TaxiDriver
{
public $name;
public function __construct($name)
{
$this->name = $name;
}

public function drive(Toyota $toyota)
{
...
}
}

$driver = new TaxiDriver();
$driver->drive(new Toyota);

那來改一改吧!
不要寫死成開 Toyota,改成開車就好了(依賴抽象),這樣隨時換開什麼車都可以。

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
32
33
34
35
36
37
abstract car
{
private $name;

public function __construct($name)
{
$this->name = $name;
}
}

class Toyota extends Car
{
...
}

class Nissan extends Car
{
...
}

class TexiDriver
{
public $name;
public function __construct($name)
{
$this->name = $name;
}

public function drive(Car $car)
{
...
}
}

$taxiDriver = new TexiDriver();
$taxiDriver->drive(new Toyota);
$taxiDriver->drive(new Nissan);

然後我們可以發現,如果需要的話,計程車司機(TexiDriver)還可以繼承人(Human)類別,然後 drive function 抽出去成介面(interface),TexiDriver 再實作 driver 介面,都可以再向上抽象,增加使用的彈性。

Reference

PHP 也有 Day #19 - PHP 返樸歸真系列之從實例學設計模式 by 大澤木小鐵 (Jace Ju)​
物件導向設計原則 SOLID
SOLID:五則皆變
The Principles of OOD