當 new User() 散落在控制器、服務、命令各處,需求變更(如改用數據庫用戶、添加緩存、切換 API 客戶端)將引發連鎖修改。工廠模式將對象創建封裝、集中、參數化,實現「依賴抽象、不依賴具體」。本文從簡單工廠、工廠方法、抽象工廠三個層次,配合 PHP 介面、類型聲明、容器綁定,構建可擴展的創建體系。
<?php
// 1. 產品介面
interface UserInterface {
public function getName(): string;
public function getEmail(): string;
}
// 2. 具體產品
class DatabaseUser implements UserInterface {
public function __construct(private int $id) {}
public function getName(): string { return "DB_User_{$this->id}"; }
public function getEmail(): string { return "user{$this->id}@db.com"; }
}
class ApiUser implements UserInterface {
public function __construct(private string $uuid) {}
public function getName(): string { return "API_User_{$this->uuid}"; }
public function getEmail(): string { return "api-{$this->uuid}@example.com"; }
}
// 3. 簡單工廠
class UserFactory {
public static function create(string $type, string $identifier): UserInterface {
return match ($type) {
'database' => new DatabaseUser((int)$identifier),
'api' => new ApiUser($identifier),
default => throw new InvalidArgumentException("Unknown user type: $type"),
};
}
}
// 4. 使用:業務代碼零 new
$user = UserFactory::create('database', '123');
echo $user->getName(); // DB_User_123
<?php
// 1. 抽象工廠介面
interface UserFactoryInterface {
public function createUser(string $identifier): UserInterface;
}
// 2. 具體工廠
class DatabaseUserFactory implements UserFactoryInterface {
public function createUser(string $identifier): UserInterface {
return new DatabaseUser((int)$identifier);
}
}
class ApiUserFactory implements UserFactoryInterface {
public function createUser(string $identifier): UserInterface {
return new ApiUser($identifier);
}
}
// 3. 客戶端依賴抽象工廠
class UserService {
public function __construct(private UserFactoryInterface $factory) {}
public function register(string $type, string $id): UserInterface {
// 這裡可根據類型選擇工廠,或由容器注入特定工廠
return $this->factory->createUser($id);
}
}
// 4. 容器綁定 (Laravel 風格)
$container->bind(UserFactoryInterface::class, fn() => new DatabaseUserFactory());
// 或運行時動態
$factory = match ($config['user_source']) {
'db' => new DatabaseUserFactory(),
'api' => new ApiUserFactory(),
};
$service = new UserService($factory);
當需要創建相關/依賴的對象族(如:不同數據庫的 Connection + Statement + Transaction):
<?php
// 1. 產品族介面
interface ConnectionInterface { public function query(string $sql); }
interface StatementInterface { public function execute(array $params); }
interface TransactionInterface { public function commit(); public function rollback(); }
// 2. 抽象工廠
interface DatabaseFactoryInterface {
public function createConnection(): ConnectionInterface;
public function createStatement(): StatementInterface;
public function createTransaction(): TransactionInterface;
}
// 3. MySQL 族
class MySqlConnection implements ConnectionInterface { /* ... */ }
class MySqlStatement implements StatementInterface { /* ... */ }
class MySqlTransaction implements TransactionInterface { /* ... */ }
class MySqlFactory implements DatabaseFactoryInterface {
public function createConnection(): ConnectionInterface { return new MySqlConnection(); }
public function createStatement(): StatementInterface { return new MySqlStatement(); }
public function createTransaction(): TransactionInterface { return new MySqlTransaction(); }
}
// 4. PostgreSQL 族
class PgSqlFactory implements DatabaseFactoryInterface { /* ... */ }
// 5. 使用
function migrate(DatabaseFactoryInterface $factory) {
$conn = $factory->createConnection();
$tx = $factory->createTransaction();
// ... 使用族內協作對象
}
PSR-11 容器本質上就是通用工廠:
<?php
// 綁定
$container->bind(UserInterface::class, fn(ContainerInterface $c) =>
new DatabaseUser($c->get('config')['db']['default_user_id'])
);
// 解析(自動遞歸解析依賴)
$user = $container->get(UserInterface::class);
// 條件綁定
$container->bind(UserInterface::class, function (ContainerInterface $c) {
return $c->get('config')['user_source'] === 'api'
? new ApiUser($c->get('api_client')->getUserId())
: new DatabaseUser($c->get('config')['db']['default_user_id']);
});
// 標籤綁定(多實現)
$container->tag(DatabaseUser::class, 'user.implementation');
$container->tag(ApiUser::class, 'user.implementation');
// 獲取所有實現
$implementations = $container->getTagged('user.implementation');
| 場景 | 推薦模式 | 關鍵點 |
|---|---|---|
| 創建邏輯固定、類型少、無測試需求 | 簡單工廠 | 靜態方法、match 表達式 |
| 類型可擴展、需測試、依賴倒置 | 工廠方法 | 介面 + 具體工廠 + 容器綁定 |
| 創建相關對象族、多平台適配 | 抽象工廠 | 族介面一致性、配置驅動選擇 |
| 現代框架應用 | 容器自動裝配 | PSR-11、自動解析、標籤、條件綁定 |
工廠模式核心是「創建與使用分離」。從 new 關鍵字分散在業務代碼,到集中在工廠方法,再到由容器統一管理生命周期,每一步都在降低耦合、提高可測試性、增強擴展性。現代 PHP 開發中,優先使用容器自動裝配,複雜創建邏輯封裝為工廠類實現介面,由容器綁定介面到工廠。記住:工廠是為了讓業務代碼專注業務,而非為了模式而模式。