跳至內容
返回

Clean Code 筆記 (2)

發佈於:  at  08:00 上午

本次是繼續上回的 Clean Code 筆記,廢話不多說,Let’s begin.

TDD

Principle

  1. 撰寫一個單元測試前不應該撰寫產品程式碼
  2. 只撰寫剛好能通過的產品程式碼
  3. 只撰寫剛好能通過當前測試失敗的產品程式碼

注意要點

TDD FIRST 原則

Class Level

單一職責原則(Single Responsibility Principle, SRP)

單一職責原則主張,一個類別或一個模組應該只能有一個,而且只能有一個被修改的理由。
個人對這段的理解是,一個類別的職責應該是很明確的,他只該負責一件事,而需要修改類別的原因,必須得是當初認為要做的那件事。比方說有一個專門處理報表 Excel 輸出的類別 ExcelObject,若今天需要做輸出 Excel 之外的事,比方說:判斷格式、字串拼接、欄位驗證、給定預設值,若因為這些理由而修改了 ExcelObject,就是違反了 SRP。

凝聚力

類別中的方法,盡量讓每個變數都被使用在每一個方法中。
當類別失去凝聚力時,就應該將它拆開。

開放閉合原則(Open-Closed Principle)

類別應該要對擴充具備開放性,但對修改具有閉合性。

隔離修改

類別之間不應該實體依賴,而是依賴抽象,透過一層抽象隔離變化,責任分明且易於測試。

System

依賴注入(Dependency Injection, DI)

將物件的建立過程從使用中分離出來,這是控制反轉(Inversion of Control, IOC)在相依性管理裡的一種應用手段。控制反轉是將某個物件的第二個職責,移至其他專注於該職責的物件裡,也因此支援了 SRP 原則。
在相依性管理的範疇中,一個物件不應該負責實體化對本身的相依,而是將責任交給外部。建議可以透過抽象工廠進行。

抽象工廠(Abstract Factory)Example

// 抽象產品:Button
interface Button {
    void render();
}

// 抽象產品:TextBox
interface TextBox {
    void render();
}

// 具體產品:WindowsButton
class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("Rendering a Windows-style Button");
    }
}

// 具體產品:WindowsTextBox
class WindowsTextBox implements TextBox {
    @Override
    public void render() {
        System.out.println("Rendering a Windows-style TextBox");
    }
}

// 具體產品:MacOSButton
class MacOSButton implements Button {
    @Override
    public void render() {
        System.out.println("Rendering a MacOS-style Button");
    }
}

// 具體產品:MacOSTextBox
class MacOSTextBox implements TextBox {
    @Override
    public void render() {
        System.out.println("Rendering a MacOS-style TextBox");
    }
}

// 抽象工廠:UIFactory
interface UIFactory {
    Button createButton();
    TextBox createTextBox();
}

// 具體工廠:WindowsFactory
class WindowsFactory implements UIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public TextBox createTextBox() {
        return new WindowsTextBox();
    }
}

// 具體工廠:MacOSFactory
class MacOSFactory implements UIFactory {
    @Override
    public Button createButton() {
        return new MacOSButton();
    }

    @Override
    public TextBox createTextBox() {
        return new MacOSTextBox();
    }
}

// 客戶端
public class AbstractFactoryExample {
    public static void main(String[] args) {
        // 客戶端選擇一個工廠
        UIFactory factory = getFactory("Windows"); // 可切換為 "MacOS"

        // 使用工廠創建產品
        Button button = factory.createButton();
        TextBox textBox = factory.createTextBox();

        // 渲染產品
        button.render();
        textBox.render();
    }

    // 工廠選擇邏輯
    private static UIFactory getFactory(String osType) {
        return switch (osType) {
            case "Windows" -> new WindowsFactory();
            case "MacOS" -> new MacOSFactory();
            default -> throw new IllegalArgumentException("Unknown OS type");
        };
    }
}

▲ 這樣的設計可以靈活切換不同風格的 UI,且對於新的 UI 主題(如 Linux),只需添加新的工廠和產品類即可,無需修改現有代碼。

橫切關注點

假設我們有一個交易系統,流程如下:

  1. 登入 -> 身分驗證 -> 付款
  2. 登入 -> 身分驗證 -> 退款

嘗試以這樣的角度去理解系統的流程,你會發現「登入」與「身分驗證」並不是真正核心的功能,且兩者重複存在。為了使我們可以更專注在真正重要的商業流程上,我們可以將那些次要的細節作為一個個切片(Aspects)從主流程切割出來,這一個步驟我們稱之為關注點分離。
而實現這樣的構想的技術就是 Java Proxy 機制,或是 AOP(又名切面導向編程)。
關於 AOP,可以參考我的另一篇文章:Spring AOP

大約整理到這邊,後面 Clean Code 的相關討論幾乎都是案例題目了,這邊就不拿出來討論了。


建議修改
在以下平台分享此文章:

上一篇
買一個domain給自己有甚麼好處?
下一篇
Clean Code 筆記 (1)