SOLID 原則 - Dependency Inversion Principle

Dependency Inversion Principle

Depend on abstractions not on concretions

所有物件的相依關係需要依賴於抽象類別,例如 contractinterfaceabstraction,而非 concretion class

白話點來解釋,我們可以想像有一個檯燈、電視以及音響,當我們要使用這些電器的時候需要提供電量給他們運作沒錯吧?

所以這些裝置會有一個插頭,提供我們插電使用

但現在想像一下,如果沒有這個插頭的話該怎辦?

我們只能把這些裝置直接拉線進牆壁通電,但這一點也不方便,所以我們有了插座,把插座接上裝置的插頭就能使用了,換句話說,當你設計這些裝置的時候,你不需要去在意他怎麼收到電的,這些裝置反而是依賴某些介面,讓裝置們能直接使用電力,這才是正確的設計流程。

DIP 原則內有兩大重點,分別是:

  1. High level modules should not depend on low level modules.
  2. Both modules should depend on abstractions.

補充說明:當 A class 去 new B class,A 就是高階模組,B為低階模組。同時contractinterfaceabstraction 這些也稱為高階模組

接下來我們用程式碼來幫助大家理解DIP 原則

1
2
3
4
5
6
7
8
9
class PasswordRemainder
{
private $dbConnection;

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

我們實作了一個密碼提醒的類別,透過Dependency Injection 的方法注入MySQLConnection 當作密碼查詢時的資料庫連線。

但是問題來了,為什麼密碼提醒這項功能要在意是透過哪種資料庫連線來啟動?我不能使用 MongoDBConenction 嗎?

這邊便違反了DIP 原則,High level module(PasswordReminder) should never depend on low level module(MySQLConnection),高階模組不應該相依於低階模組,因此我們需要一個 abstraction 來改變彼此的相依關係。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
interface ConnectionInterface
{
public function connect();
}

class MySQLConnection implements ConnectionInterface
{
public function connect()
{
//
}
}

class PasswordReminder
{
private $dbConnection;

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

重新回到我們的相依關係,目前可以看到High level module(PasswordReminder) depend on abstraction(ConnectionInterface)

除了High level module 外,Low level module(MySQLConnection) also depend on abstraction(ConnectionInterface),所有的模組都相依於 abstraction 上了

這麼做有什麼好處? 當然有,我們可以得到一個高可用及高擴充性的 PasswordReminder,因為PasswordReminder 不需要了解它實際上是透過哪種資料庫連線取得相關資料的,他只需要知道他有 connect() 方法可以使用即可。

以上便是DIP 原則的介紹。

對我來說,Dependency Inversion Principle 是SOLID 最精華的地方,它的核心原則,或者說是整個物件導向的核心原則:

Program to an interface, not an implementation.

對於想更往上一層樓的RD 們,這句話非常值得大家反思。

SOLID 的五大原則正式告一段落,如果沒看懂仔細多看幾遍,但如果都看得懂的話非常恭喜,你們已經掌握物件導向中最重要的幾項設計原則了。