用 TypeScript 簡單介紹 SOLID 原則裡面的 D

此為 SOLID 原則介紹的系列文章之一,所有文章的連結如下。

SOLID 原則中的 D


來到 SOLID 原則中最後一個原則,也就是依賴倒轉原則 (Dependency inversion principle)。

DIS 最主要的目的在於解耦 (Decoupling),其概念如下。

高層次的類別不應該依賴於低層次的類別,兩者都應該依賴於抽象的介面。
抽象介面不應該依賴於具體的實作,具體的實作應該依賴於抽象介面。

什麼是高層次與低層次的類別呢?

  • 低層次的類別,用來實作基礎操作,例如磁碟操作網路數據傳輸資料庫連線
  • 高層次的類別,包含複雜的業務邏輯,操作低層次的類別來執行特定操作。

有時候在開發新系統的時候,我們可能會先設計低層次的類別,然後才會開始開發高層次的類別。

這樣開發流程十分常見,因為在低層次類別的功能還沒有確定與實作之前,我們也無法確定高層次類別可以實現哪些功能。

但這樣的開發流程,容易讓用來實現業務邏輯的高層次類別依賴於低層次的類別

依賴倒轉原則建議改變這種依賴方式。

  1. 最好使用業務術語來命名高層次類別的方法,如 BudgetReport
  2. 基於抽象介面建立高層次類別,而不是基於低層次的具體類別,這會比原始的依賴關係靈活很多。
  3. 一旦低層次的類別實現這些介面,他們將依賴於業務邏輯層,從而倒轉了原始的依賴關係。

依賴倒轉原則通常會伴隨著開放封閉原則,無須修改已存在的類別,就能擴展不同的業務邏輯。

舉個例子,高層次的預算報告類別 BudgetReport,使用低層次的資料庫類別 MySqlDatabase 來讀取和儲存資料,這代表低層次類別的任何改變 (例如資料庫發布新版本時),都會影響高層次的類別,但高層次的類別不應該去關注資料存儲的細節

class MySqlDatabase {
    insert() {
        // ...
    }

    update() {
        // ...
    }

    delete() {
        // ...
    }
}

class BudgetReport {
    private mySqlDatabase: MySqlDatabase

    constructor(mySqlDatabase: MySqlDatabase) {
        this.mySqlDatabase = mySqlDatabase
    }

    open(date: string) {
        //...
    }

    save() {

    }
}

可以看到上述的程式碼,高層次的類別 BudgetReport 依賴於低層次的類別 MySqlDatabase

要解決這個問題,我們可以建立一個描述讀寫操作的高層次介面 Database,並讓預算報告類別 BudgetReport 使用這個介面,而不是使用低層次的類別 MySqlDatabase

interface Database {
    insert(): void

    update(): void

    delete(): void
}

class MySql implements Database {
    insert(): void {
        // ...
    }

    update(): void {
        // ...
    }

    delete(): void {
        // ...
    }
}

class MongoDB implements Database {
    insert(): void {
        // ...
    }

    update(): void {
        // ...
    }

    delete(): void {
        // ...
    }
}

class BudgetReport {
    private database: Database

    constructor(database: Database) {
        this.database = database
    }

    open(date: string) {
        //...
    }

    save() {

    }
}

修改之後,低層次的類別依賴於高層次的抽象,原始的依賴關係被倒轉。

Laracasts 的講師是這麼說明依賴倒轉原則的。

Depends on abstractions, not on concretions.
依賴於抽象,而非具體。

參考資料


Laracasts - SOLID Principles in PHP
Refactoring Guru - Design Patterns

sharkHead
written by
sharkHead
後端工程師, PHP 基金會每月 10 刀贊助人
稍微擅長 PHP、Python 與 Google 搜尋,偶爾寫寫 TypeScript