好的,我們來探討設計模式中的兩個常見且重要的模式:Singleton (單例模式) 和 Factory (工廠模式),並說明它們各自的使用情境。
設計模式是解決軟體設計中常見問題的經過驗證的解決方案。它們是經驗的結晶,旨在使程式碼更具可讀性、可維護性、可擴展性和重用性。
1. Singleton Pattern (單例模式)
定義
單例模式 是一種創建型設計模式,它確保一個類別只有一個實例,並提供一個全域的存取點來獲取這個唯一的實例。
核心概念
- 唯一實例: 任何時候,該類別只能有一個物件實例存在於記憶體中。
- 自實例化: 類別本身負責創建自己的唯一實例。
- 全域存取點: 提供一個靜態方法 (通常是
getInstance()
) 供外部獲取該唯一實例。 - 私有建構子: 將建構子設為
private
或protected
,防止外部直接透過new
關鍵字創建新的實例。
使用情境
單例模式通常適用於以下場景:
-
日誌記錄器 (Logger):
- 情境: 在一個應用程式中,你可能希望所有的日誌訊息都寫入到同一個日誌檔案中,或透過同一個日誌服務發送。如果有多個日誌記錄器實例,可能會導致檔案鎖定問題、資料寫入混亂或資源浪費。
- 應用: 將日誌記錄器設計為單例模式。所有需要記錄日誌的地方都呼叫
Logger::getInstance()->log(...)
。這樣可以確保所有日誌操作都透過同一個實例進行,有效管理資源。
-
配置管理器 (Configuration Manager):
- 情境: 應用程式的配置資訊 (如資料庫連線字串、API 金鑰等) 通常在應用程式啟動時載入一次,並且在整個應用程式生命週期中都需要被存取。
- 應用: 將配置管理器設計為單例。當首次請求配置時,它會載入並解析配置檔案,然後將該實例保留下來。後續所有對配置的存取都將透過這個唯一的實例進行,避免重複載入和解析,提高效率。
-
資料庫連線池 (Database Connection Pool):
- 情境: 建立資料庫連線是耗費資源的操作。在許多應用程式中,需要限制同時存在的資料庫連線數量,並重用現有的連線。
- 應用: 可以將資料庫連線池設計為單例。它負責管理連線的創建、分配和回收。所有的資料庫操作都從這個唯一的連線池獲取連線,而不是每次都創建新的連線。
-
快取管理器 (Cache Manager):
- 情境: 應用程式中通常會有快取機制來提高資料讀取速度。為了確保快取資料的一致性並有效管理記憶體,通常只需要一個快取管理器。
- 應用: 將快取管理器設計為單例。所有快取讀寫操作都通過該唯一實例進行。
-
應用程式核心服務 (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): 實現創建者介面或繼承抽象類別,覆寫工廠方法來創建特定產品的實例。
使用情境
工廠模式適用於以下情況:
-
資料庫驅動 (Database Drivers):
- 情境: 你的應用程式可能需要支援多種資料庫 (MySQL, PostgreSQL, SQLite)。每種資料庫都有自己的連線和查詢方式。
- 應用:
- 定義一個
DbConnectionInterface
介面,包含connect()
,query()
等方法。 - 為每種資料庫創建
MySqlConnection
,PgSqlConnection
等具體實現類別。 - 創建一個
ConnectionFactory
工廠類別,其中有一個createConnection(string $type)
方法。根據$type
參數的不同,該方法會返回相應的DbConnectionInterface
實例。
- 定義一個
- 好處: 使用者不需要知道如何實例化特定的資料庫連線類別,只需要告訴工廠它需要哪種連線。當新增或更換資料庫類型時,只需要修改工廠類別,而不需要修改所有使用連線的程式碼。
-
檔案解析器 (File Parsers):
- 情境: 應用程式需要處理多種檔案格式 (JSON, XML, CSV)。
- 應用:
- 定義一個
FileParserInterface
介面,包含parse(string $filePath)
方法。 - 實現
JsonParser
,XmlParser
,CsvParser
等類別。 - 創建
FileParserFactory
,根據檔案副檔名或指定類型來返回正確的解析器實例。
- 定義一個
- 好處: 應用程式的其他部分可以統一地透過
FileParserFactory
獲取解析器,並呼叫parse()
方法,無需關心底層是哪種具體的解析邏輯。
-
不同類型物件的初始化 (Varying Object Initialization):
- 情境: 你需要創建的物件類型在執行時才能確定,或者物件的創建過程很複雜,包含多個步驟或依賴。
- 應用: 將複雜的創建邏輯封裝到工廠中。例如,一個遊戲中的敵人生成器,可以根據遊戲關卡或玩家選擇來創建不同類型的敵人 (步兵、弓箭手、法師),每個敵人的創建可能涉及到不同的屬性設定或裝備初始化。
-
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):將物件的創建過程與使用過程分離。適用於需要根據不同條件創建不同類型的物件,或物件創建過程複雜的場景,提高系統的靈活性和可擴展性。
沒有留言:
張貼留言