Factory Method Pattern,PHP 工廠模式

Feature image for Factory Method Pattern,PHP 工廠模式

簡介

Factory Method Pattern(工廠方法模式)是一種專門用於處理物件創建問題的設計模式。本文將先解釋什麼是 Factory Method Pattern,然後用一個簡單易懂的例子來說明其運作方式。接著會說明什麼情況下應該使用這個模式,並通過一個以咖啡為主題的 PHP 程式範例來進一步說明。最後會比較 Factory Method Pattern 和其他類似的設計模式,幫助讀者更好地理解它們之間的差異。

什麼是 Factory Method Pattern

Factory Method Pattern 是一種創建型設計模式,它提供了一個介面用於創建物件,但允許子類別改變將要創建的物件的類型。透過這種方式,我們可以將物件創建的程式碼和實際使用物件的程式碼分離,大幅增加了程式碼的靈活性和可維護性。

生活中的例子:

想像你走進一家咖啡店,你不需要知道咖啡是如何製作的,只需要點單即可。咖啡店(Factory)會根據你的需求(參數)為你製作一杯咖啡(物件)。你不需要了解咖啡的製作過程,只需要知道你想要什麼類型的咖啡,工廠就會為你處理所有的細節。

什麼狀況適合使用 Factory Method Pattern

當你有一個超類別,它有多個子類別,並且基於某些條件,你必須返回其中一個子類別的實例時,最好使用 Factory Method Pattern。這樣可以隱藏實例創建的邏輯,並使程式碼更容易擴展。

適用情境:

  • 當你需要在執行時期決定要創建哪種類型的物件時
  • 當物件創建的邏輯變得複雜,需要集中管理時
  • 當你想要降低程式碼之間的耦合度時
  • 當你預期未來可能需要新增新的物件類型時

例如,一個咖啡店可能有多種咖啡,每種咖啡的製作過程都略有不同。使用 Factory Method,我們可以輕鬆地新增更多種咖啡,而不影響現有程式碼。當需要新增新的咖啡類型時,只需要在工廠類別中添加新的創建邏輯,而不需要修改使用咖啡的程式碼。

範例教學

在這個範例中,我們會創建一個 CoffeeFactory 類別,它可以根據不同的需求製作不同種類的咖啡。我們將從一個簡單的範例開始,然後逐步改善它,展示 Factory Method Pattern 的優勢。

原始範例,未使用 Factory Method

<?php
class Coffee {
    public function brew() {
        echo "Brewing a regular coffee\n";
    }
}

$coffee = new Coffee();
$coffee->brew();
?>

缺點

這種方式的主要缺點是它不夠靈活。如果我們想添加更多種咖啡,必須在每個需要的地方自己創建物件實例,這會導致程式碼重複,並且增加了維護的困難度。如果使用工廠模式,就不必深入了解各種不同的咖啡類別,可以降低物件間的耦合,讓程式碼更加模組化和易於維護。

改善範例,使用 Factory Method

<?php
interface Coffee {
    public function brew();
}

class RegularCoffee implements Coffee {
    public function brew() {
        echo "Brewing a regular coffee\n";
    }
}

class Espresso implements Coffee {
    public function brew() {
        echo "Brewing an espresso\n";
    }
}

class CoffeeFactory {
    public static function createCoffee($type) {
        if ($type === 'regular') {
            return new RegularCoffee();
        } elseif ($type === 'espresso') {
            return new Espresso();
        }
        throw new InvalidArgumentException("Unknown coffee type: $type");
    }
}

$coffee = CoffeeFactory::createCoffee('espresso');
$coffee->brew();
?>

factory method pattern class diagram

咖啡工廠類別圖

優點

使用 Factory Method Pattern 帶來以下好處:

  • 降低耦合度:使用咖啡的程式碼不需要直接依賴具體的咖啡類別,只需要依賴 Coffee 介面
  • 易於擴展:當需要新增新的咖啡類型時,只需要在工廠類別中添加新的創建邏輯,不需要修改使用咖啡的程式碼
  • 集中管理:所有物件創建的邏輯都集中在工廠類別中,更容易維護和測試
  • 提高靈活性:可以根據不同的條件動態創建不同類型的物件

更多延伸範例

我們可以繼續擴展這個範例,例如添加一個 Latte(拿鐵)類別。這個例子展示了 Factory Method Pattern 的擴展性。

class Latte implements Coffee {
    public function brew() {
        echo "Brewing a latte\n";
    }
}

// 更新 CoffeeFactory
class CoffeeFactory {
    public static function createCoffee($type) {
        if ($type === 'regular') {
            return new RegularCoffee();
        } elseif ($type === 'espresso') {
            return new Espresso();
        } elseif ($type === 'latte') {
            return new Latte();
        }
        throw new InvalidArgumentException("Unknown coffee type: $type");
    }
}

// 工廠現在可以生產拿鐵,使用者只需知道拿鐵的名稱即可,不需要了解工廠背後的運作細節
$coffee = CoffeeFactory::createCoffee('latte');
$coffee->brew();

從這個例子可以看出,當我們需要新增新的咖啡類型時,只需要:

  1. 創建新的咖啡類別並實作 Coffee 介面
  2. 在工廠類別中添加創建該類別的邏輯

使用咖啡的程式碼完全不需要修改,這就是 Factory Method Pattern 帶來的靈活性。

其他類似的 Design Pattern

Factory Method Pattern 和 Abstract Factory Pattern 都是用於創建物件的設計模式,但它們的應用場景不同。

主要區別:

  • Factory Method Pattern:用於創建單一類型的物件。它透過一個方法來創建物件,讓子類別決定要實例化哪個類別。
  • Abstract Factory Pattern:用於創建一系列相關或依賴的物件。它提供一個介面來創建多個相關的物件,而不需要指定它們的具體類別。
Design Pattern主要用途適用情境
Factory Method創建單一類型的物件當需要根據條件創建不同類型的物件時
Abstract Factory創建一系列相關的物件當需要創建多個相關或依賴的物件時

選擇建議:

  • 如果你只需要創建單一類型的物件,使用 Factory Method Pattern
  • 如果你需要創建一組相關的物件(例如,創建一套 UI 元件),使用 Abstract Factory Pattern

總結

Factory Method Pattern 是一個非常實用的設計模式,它能夠:

  • 將物件創建的邏輯與使用物件的程式碼分離
  • 降低程式碼之間的耦合度
  • 提高程式碼的可維護性和擴展性
  • 讓程式碼更加模組化和易於測試

當你需要在執行時期根據條件創建不同類型的物件時,Factory Method Pattern 是一個很好的選擇。它讓你的程式碼更加靈活,也更容易應對未來的需求變化。

參考來源

  1. Wikipedia: Factory Method Pattern
  2. GeeksforGeeks: Factory Method Pattern
  3. Refactoring Guru: Factory Method
  4. Tutorialspoint: Factory Method Pattern
  5. Stack Overflow: What is Factory Method Pattern?