工廠模式 是創建型模式核心,透過統一介面建立物件,隱藏具體建立邏輯 (參數計算、子類選擇、依賴注入)。本文實作簡單工廠、工廠方法、抽象工廠三種變體。
單一類別根據參數決定建立何種物件。非 GoF 正式模式,但極實用。
<?php
// 1. 產品介面
interface DatabaseConnection {
public function connect(): void;
public function query(string $sql): iterable;
}
// 2. 具體產品
class MySQLConnection implements DatabaseConnection {
public function __construct(private string $host, private string $user, private string $pass, private string $db) {}
public function connect(): void { /* PDO 連線 */ }
public function query(string $sql): iterable { /* ... */ }
}
class PostgreSQLConnection implements DatabaseConnection {
public function __construct(private string $host, private string $user, private string $pass, private string $db) {}
public function connect(): void { /* PDO 連線 */ }
public function query(string $sql): iterable { /* ... */ }
}
// 3. 簡單工廠
class ConnectionFactory {
public static function create(string $driver, array $config): DatabaseConnection {
return match($driver) {
'mysql' => new MySQLConnection($config['host'], $config['user'], $config['pass'], $config['db']),
'postgresql' => new PostgreSQLConnection($config['host'], $config['user'], $config['pass'], $config['db']),
'sqlite' => new SQLiteConnection($config['path']),
default => throw new InvalidArgumentException("Unsupported driver: $driver"),
};
}
}
// 4. 客戶端:無需知道具體類別
$config = ['driver' => 'mysql', 'host' => 'localhost', 'user' => 'root', 'pass' => '', 'db' => 'app'];
$db = ConnectionFactory::create($config['driver'], $config);
$db->connect();
?>
定義建立物件的介面,由子類別決定實例化哪個類別。延遲建立到子類別。
<?php
// 1. 抽象創建者
abstract class DatabaseManager {
// 工廠方法:子類別實作
abstract protected function createConnection(array $config): DatabaseConnection;
// 模板方法:定義流程
public function getConnection(array $config): DatabaseConnection {
$conn = $this->createConnection($config);
$conn->connect();
return $conn;
}
}
// 2. 具體創建者
class MySQLManager extends DatabaseManager {
protected function createConnection(array $config): DatabaseConnection {
return new MySQLConnection($config['host'], $config['user'], $config['pass'], $config['db']);
}
}
class PostgreSQLManager extends DatabaseManager {
protected function createConnection(array $config): DatabaseConnection {
return new PostgreSQLConnection($config['host'], $config['user'], $config['pass'], $config['db']);
}
}
// 3. 使用:針對特定資料庫類型
$manager = new MySQLManager(); // 或從配置決定
$db = $manager->getConnection($config);
?>
提供介面建立相關/依賴物件家族,無需指定具體類別。
<?php
// 1. 抽象產品家族
interface Connection { public function query(string $sql): iterable; }
interface Transaction { public function begin(): void; public function commit(): void; public function rollback(): void; }
// 2. MySQL 家族
class MySQLConnection implements Connection { /* ... */ }
class MySQLTransaction implements Transaction { /* ... */ }
// 3. PostgreSQL 家族
class PostgreSQLConnection implements Connection { /* ... */ }
class PostgreSQLTransaction implements Transaction { /* ... */ }
// 4. 抽象工廠
interface DatabaseFactory {
public function createConnection(): Connection;
public function createTransaction(): Transaction;
}
// 5. 具體工廠
class MySQLFactory implements DatabaseFactory {
public function createConnection(): Connection { return new MySQLConnection(); }
public function createTransaction(): Transaction { return new MySQLTransaction(); }
}
class PostgreSQLFactory implements DatabaseFactory {
public function createConnection(): Connection { return new PostgreSQLConnection(); }
public function createTransaction(): Transaction { return new PostgreSQLTransaction(); }
}
// 6. 客戶端:操作整個家族
function migrate(DatabaseFactory $factory) {
$conn = $factory->createConnection();
$tx = $factory->createTransaction();
$tx->begin();
// 使用 $conn 和 $tx 進行遷移...
$tx->commit();
}
// 根據配置選擇工廠
$factory = match($config['driver']) {
'mysql' => new MySQLFactory(),
'pgsql' => new PostgreSQLFactory(),
};
migrate($factory);
?>
| 框架 | 工廠實作 | 用途 |
|---|---|---|
| Laravel | Factory::create(), ModelFactory, Manager (DatabaseManager, CacheManager) |
模型測試資料、驅動管理 (DB、Cache、Queue、Filesystem) |
| Symfony | Service Factory、AbstractFactory |
服務容器建立複雜服務 |
| Doctrine | EntityManager::getRepository(), ProxyFactory |
實體倉庫、延遲載入代理 |
| PSR-11 | ContainerInterface::get() |
標準化服務工廠 |
<?php
// 參數化工廠:建立時注入運行時參數
class UserFactory {
public function __construct(
private PasswordHasher $hasher,
private EventDispatcher $dispatcher
) {}
public function create(array $data): User {
$user = new User();
$user->name = $data['name'];
$user->email = $data['email'];
$user->password = $this->hasher->hash($data['password']);
$user->created_at = new DateTimeImmutable();
$this->dispatcher->dispatch(new UserRegistered($user));
return $user;
}
}
// 延遲工廠:只有真正需要時才建立昂貴物件
class LazyFactory {
private ?ExpensiveService $instance = null;
public function __construct(private callable $factory) {}
public function get(): ExpensiveService {
return $this->instance ??= ($this->factory)();
}
}
// 使用
$lazyDb = new LazyFactory(fn() => ConnectionFactory::create('mysql', $config));
// 第一次呼叫 get() 才真正建立連線
$db = $lazyDb->get();
?>
| 模式 | 結構 | 靈活性 | 複雜度 | 適用場景 |
|---|---|---|---|---|
| 簡單工廠 | 單一類別 + 靜態方法 | 低 (修改工廠新增類型) | 低 | 類型固定、建立邏輯簡單 |
| 工廠方法 | 抽象創建者 + 具體子類 | 中 (新增子類別) | 中 | 框架擴展點、插件系統 |
| 抽象工廠 | 工廠介面 + 產品家族 | 高 (整個家族切換) | 高 | 跨平台、多資料庫、UI 主題家族 |