2025年6月10日 星期二

PHP設計模式(如 Singleton、Factory)的使用情境。

 好的,我們來探討設計模式中的兩個常見且重要的模式:Singleton (單例模式)Factory (工廠模式),並說明它們各自的使用情境。

設計模式是解決軟體設計中常見問題的經過驗證的解決方案。它們是經驗的結晶,旨在使程式碼更具可讀性、可維護性、可擴展性和重用性。


1. Singleton Pattern (單例模式)

定義

單例模式 是一種創建型設計模式,它確保一個類別只有一個實例,並提供一個全域的存取點來獲取這個唯一的實例。

核心概念

  • 唯一實例: 任何時候,該類別只能有一個物件實例存在於記憶體中。
  • 自實例化: 類別本身負責創建自己的唯一實例。
  • 全域存取點: 提供一個靜態方法 (通常是 getInstance()) 供外部獲取該唯一實例。
  • 私有建構子: 將建構子設為 privateprotected,防止外部直接透過 new 關鍵字創建新的實例。

使用情境

單例模式通常適用於以下場景:

  1. 日誌記錄器 (Logger):

    • 情境: 在一個應用程式中,你可能希望所有的日誌訊息都寫入到同一個日誌檔案中,或透過同一個日誌服務發送。如果有多個日誌記錄器實例,可能會導致檔案鎖定問題、資料寫入混亂或資源浪費。
    • 應用: 將日誌記錄器設計為單例模式。所有需要記錄日誌的地方都呼叫 Logger::getInstance()->log(...)。這樣可以確保所有日誌操作都透過同一個實例進行,有效管理資源。
  2. 配置管理器 (Configuration Manager):

    • 情境: 應用程式的配置資訊 (如資料庫連線字串、API 金鑰等) 通常在應用程式啟動時載入一次,並且在整個應用程式生命週期中都需要被存取。
    • 應用: 將配置管理器設計為單例。當首次請求配置時,它會載入並解析配置檔案,然後將該實例保留下來。後續所有對配置的存取都將透過這個唯一的實例進行,避免重複載入和解析,提高效率。
  3. 資料庫連線池 (Database Connection Pool):

    • 情境: 建立資料庫連線是耗費資源的操作。在許多應用程式中,需要限制同時存在的資料庫連線數量,並重用現有的連線。
    • 應用: 可以將資料庫連線池設計為單例。它負責管理連線的創建、分配和回收。所有的資料庫操作都從這個唯一的連線池獲取連線,而不是每次都創建新的連線。
  4. 快取管理器 (Cache Manager):

    • 情境: 應用程式中通常會有快取機制來提高資料讀取速度。為了確保快取資料的一致性並有效管理記憶體,通常只需要一個快取管理器。
    • 應用: 將快取管理器設計為單例。所有快取讀寫操作都通過該唯一實例進行。
  5. 應用程式核心服務 (Application Core Services):

    • 情境: 某些全域性的服務,如事件分發器、任務調度器,在整個應用程式中只需要一個中心點來管理和協調。
    • 應用: 這些服務很適合使用單例模式。

Laravel 中的單例

Laravel 框架本身廣泛使用了單例模式,但通常不是透過手動實現 getInstance() 靜態方法,而是透過其服務容器 (Service Container) 來實現。

  • singleton() 方法: 在服務提供者 (Service Provider) 中,你可以使用 $this->app->singleton() 方法來綁定一個單例。
    PHP
    // In a Service Provider
    public function register()
    {
        $this->app->singleton(MyService::class, function ($app) {
            return new MyService();
        });
    
        // 或者更簡潔地綁定一個類別為單例
        // $this->app->singleton(AnotherService::class);
    }
    
    MyService 被解析時,服務容器只會建立一個實例,之後每次請求都會返回同一個實例。

2. Factory Pattern (工廠模式)

定義

工廠模式 是一種創建型設計模式,它提供一個介面或抽象類別來創建物件,但讓子類別決定要實例化哪個類別。它將物件的創建邏輯從使用物件的程式碼中分離出來。

工廠模式通常分為:

  • 簡單工廠 (Simple Factory): 最簡單的形式,一個工廠類別負責創建所有產品。
  • 工廠方法 (Factory Method): 定義一個用於建立物件的介面,讓子類別決定實例化哪一個類別。工廠方法讓類別把實例化延遲到子類別。
  • 抽象工廠 (Abstract Factory): 提供一個介面,用於創建一系列相關或相互依賴的物件,而無需指定它們的具體類別。

這裡我們主要以工廠方法為例來解釋,因為它更符合「模式」的定義,而簡單工廠有時被視為一種編程習慣而不是正式的設計模式。

核心概念 (以工廠方法為例)

  • 產品介面/抽象類別 (Product Interface/Abstract Class): 定義被創建物件的共同介面或抽象類別。
  • 具體產品 (Concrete Products): 實現產品介面或繼承抽象類別的具體物件。
  • 創建者介面/抽象類別 (Creator Interface/Abstract Class): 聲明工廠方法,返回一個產品物件。
  • 具體創建者 (Concrete Creators): 實現創建者介面或繼承抽象類別,覆寫工廠方法來創建特定產品的實例。

使用情境

工廠模式適用於以下情況:

  1. 資料庫驅動 (Database Drivers):

    • 情境: 你的應用程式可能需要支援多種資料庫 (MySQL, PostgreSQL, SQLite)。每種資料庫都有自己的連線和查詢方式。
    • 應用:
      • 定義一個 DbConnectionInterface 介面,包含 connect(), query() 等方法。
      • 為每種資料庫創建 MySqlConnection, PgSqlConnection 等具體實現類別。
      • 創建一個 ConnectionFactory 工廠類別,其中有一個 createConnection(string $type) 方法。根據 $type 參數的不同,該方法會返回相應的 DbConnectionInterface 實例。
    • 好處: 使用者不需要知道如何實例化特定的資料庫連線類別,只需要告訴工廠它需要哪種連線。當新增或更換資料庫類型時,只需要修改工廠類別,而不需要修改所有使用連線的程式碼。
  2. 檔案解析器 (File Parsers):

    • 情境: 應用程式需要處理多種檔案格式 (JSON, XML, CSV)。
    • 應用:
      • 定義一個 FileParserInterface 介面,包含 parse(string $filePath) 方法。
      • 實現 JsonParser, XmlParser, CsvParser 等類別。
      • 創建 FileParserFactory,根據檔案副檔名或指定類型來返回正確的解析器實例。
    • 好處: 應用程式的其他部分可以統一地透過 FileParserFactory 獲取解析器,並呼叫 parse() 方法,無需關心底層是哪種具體的解析邏輯。
  3. 不同類型物件的初始化 (Varying Object Initialization):

    • 情境: 你需要創建的物件類型在執行時才能確定,或者物件的創建過程很複雜,包含多個步驟或依賴。
    • 應用: 將複雜的創建邏輯封裝到工廠中。例如,一個遊戲中的敵人生成器,可以根據遊戲關卡或玩家選擇來創建不同類型的敵人 (步兵、弓箭手、法師),每個敵人的創建可能涉及到不同的屬性設定或裝備初始化。
  4. UI 組件的創建 (UI Component Creation):

    • 情境: 在跨平台 UI 應用程式中,相同的邏輯可能需要生成不同作業系統風格的按鈕、文字框等。
    • 應用: 可以有一個 UIComponentFactory,在 Windows 系統上返回 WinButton,在 Mac 系統上返回 MacButton,但兩者都實作 ButtonInterface

Laravel 中的工廠模式

Laravel 也大量使用工廠模式,尤其是 Illuminate\Database\Eloquent\Factories

  • Model Factories: 當你使用 php artisan make:factory UserFactory 創建模型工廠時,它就是一個用於創建 User 模型實例的工廠。這允許你輕鬆地為測試或填充資料庫創建大量的假資料。
    PHP
    // database/factories/UserFactory.php
    class UserFactory extends Factory
    {
        protected $model = User::class;
    
        public function definition()
        {
            return [
                'name' => $this->faker->name(),
                'email' => $this->faker->unique()->safeEmail(),
                'email_verified_at' => now(),
                'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9zO5rQedjOAwrcrWq/C7q.', // password
                'remember_token' => Str::random(10),
            ];
        }
    }
    
    // 在 Seeder 或測試中
    User::factory()->count(10)->create(); // 使用工廠創建10個使用者
    
    這裡的 factory() 方法和工廠類本身就是工廠模式的體現,它們負責生成模型實例。

總結來說:

  • 單例模式 (Singleton)保證只有一個實例,並提供全域存取點。適用於全域資源管理、配置、日誌等。
  • 工廠模式 (Factory):將物件的創建過程與使用過程分離。適用於需要根據不同條件創建不同類型的物件,或物件創建過程複雜的場景,提高系統的靈活性和可擴展性。

沒有留言:

張貼留言

熱門文章