本文目录导读:

我会为你详细讲解 PHP 项目中工厂模式与抽象工厂模式的区别、实现方式及应用场景,并配合实际代码示例。
工厂模式(Factory Pattern)
核心概念
工厂模式定义一个创建对象的接口,让子类决定实例化哪一个类,它封装了对象创建的逻辑。
适用场景
- 当需要根据条件动态创建不同类型的对象时
- 当对象创建过程复杂,需要集中管理时
- 当需要解耦客户端代码与具体产品类时
PHP 实现示例
<?php
// 1. 产品接口
interface Logger {
public function log(string $message): void;
}
// 2. 具体产品实现
class FileLogger implements Logger {
private string $filePath;
public function __construct(string $filePath) {
$this->filePath = $filePath;
}
public function log(string $message): void {
file_put_contents($this->filePath, $message . PHP_EOL, FILE_APPEND);
echo "FileLogger: 记录日志到文件 {$this->filePath}\n";
}
}
class DatabaseLogger implements Logger {
private string $connectionString;
public function __construct(string $connectionString) {
$this->connectionString = $connectionString;
}
public function log(string $message): void {
// 模拟数据库日志记录
echo "DatabaseLogger: 记录日志到数据库 {$this->connectionString}\n";
}
}
class CloudLogger implements Logger {
private string $apiKey;
public function __construct(string $apiKey) {
$this->apiKey = $apiKey;
}
public function log(string $message): void {
echo "CloudLogger: 记录日志到云服务\n";
}
}
// 3. 工厂类
class LoggerFactory {
public static function createLogger(string $type, array $config = []): Logger {
switch ($type) {
case 'file':
$filePath = $config['file_path'] ?? '/var/log/app.log';
return new FileLogger($filePath);
case 'database':
$connectionString = $config['connection'] ?? 'mysql://localhost:3306';
return new DatabaseLogger($connectionString);
case 'cloud':
$apiKey = $config['api_key'] ?? 'default-key';
return new CloudLogger($apiKey);
default:
throw new InvalidArgumentException("不支持的日志类型: {$type}");
}
}
}
// 4. 客户端代码
class Application {
private Logger $logger;
public function __construct(string $logType, array $config = []) {
// 客户端不需要知道日志类的具体创建细节
$this->logger = LoggerFactory::createLogger($logType, $config);
}
public function run(): void {
$this->logger->log("应用启动成功");
$this->logger->log("用户登录系统");
}
}
// 使用示例
try {
$app1 = new Application('file', ['file_path' => './logs/app.log']);
$app1->run();
$app2 = new Application('database', ['connection' => 'mysql://user:pass@localhost']);
$app2->run();
$app3 = new Application('cloud', ['api_key' => 'abc123']);
$app3->run();
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
抽象工厂模式(Abstract Factory Pattern)
核心概念
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类,它是工厂模式的升级版。
适用场景
- 系统需要独立于产品的创建、组合和表示
- 系统需要产品族的概念
- 需要提供产品类库,只想暴露接口而非实现
PHP 实现示例
<?php
// ========== 产品族1: 按钮 ==========
interface Button {
public function render(): string;
public function onClick(): void;
}
class WindowsButton implements Button {
public function render(): string {
return "渲染 Windows 风格的按钮";
}
public function onClick(): void {
echo "Windows 按钮被点击\n";
}
}
class MacButton implements Button {
public function render(): string {
return "渲染 Mac 风格的按钮";
}
public function onClick(): void {
echo "Mac 按钮被点击\n";
}
}
class LinuxButton implements Button {
public function render(): string {
return "渲染 Linux 风格的按钮";
}
public function onClick(): void {
echo "Linux 按钮被点击\n";
}
}
// ========== 产品族2: 文本框 ==========
interface TextBox {
public function render(): string;
public function getText(): string;
}
class WindowsTextBox implements TextBox {
public function render(): string {
return "渲染 Windows 风格的文本框";
}
public function getText(): string {
return "Windows 文本框内容";
}
}
class MacTextBox implements TextBox {
public function render(): string {
return "渲染 Mac 风格的文本框";
}
public function getText(): string {
return "Mac 文本框内容";
}
}
class LinuxTextBox implements TextBox {
public function render(): string {
return "渲染 Linux 风格的文本框";
}
public function getText(): string {
return "Linux 文本框内容";
}
}
// ========== 抽象工厂 ==========
interface GUIFactory {
public function createButton(): Button;
public function createTextBox(): TextBox;
}
// ========== 具体工厂 ==========
class WindowsFactory implements GUIFactory {
public function createButton(): Button {
return new WindowsButton();
}
public function createTextBox(): TextBox {
return new WindowsTextBox();
}
}
class MacFactory implements GUIFactory {
public function createButton(): Button {
return new MacButton();
}
public function createTextBox(): TextBox {
return new MacTextBox();
}
}
class LinuxFactory implements GUIFactory {
public function createButton(): Button {
return new LinuxButton();
}
public function createTextBox(): TextBox {
return new LinuxTextBox();
}
}
// ========== 客户端代码 ==========
class ApplicationUI {
private Button $button;
private TextBox $textBox;
public function __construct(GUIFactory $factory) {
// 客户端只知道使用工厂,不知道具体产品
$this->button = $factory->createButton();
$this->textBox = $factory->createTextBox();
}
public function render(): void {
echo $this->button->render() . "\n";
echo $this->textBox->render() . "\n";
$this->button->onClick();
echo "文本框内容: " . $this->textBox->getText() . "\n";
}
}
// ========== 扩展:工厂选择器 ==========
class UIFactorySelector {
public static function getFactory(string $osType): GUIFactory {
return match ($osType) {
'windows' => new WindowsFactory(),
'mac' => new MacFactory(),
'linux' => new LinuxFactory(),
default => throw new InvalidArgumentException("不支持的 OS: {$osType}")
};
}
}
// ========== 使用示例 ==========
try {
echo "=== Windows UI ===\n";
$windowsApp = new ApplicationUI(new WindowsFactory());
$windowsApp->render();
echo "\n=== Mac UI ===\n";
$macApp = new ApplicationUI(new MacFactory());
$macApp->render();
echo "\n=== Linux UI ===\n";
$linuxApp = new ApplicationUI(new LinuxFactory());
$linuxApp->render();
echo "\n=== 使用工厂选择器 ===\n";
$osType = 'windows';
$app = new ApplicationUI(UIFactorySelector::getFactory($osType));
$app->render();
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
两者的核心区别
| 特性 | 工厂模式 | 抽象工厂模式 |
|---|---|---|
| 创建对象数量 | 创建单一产品 | 创建产品族(多个相关产品) |
| 复杂度 | 较低 | 较高 |
| 扩展维度 | 新增产品类型(纵向) | 新增产品族(横向)或产品种类 |
| 客户端耦合 | 耦合单一产品接口 | 耦合多个产品接口 |
| 典型应用 | 日志系统、数据库连接 | UI组件库、跨平台工具集 |
混合使用示例(工厂模式 + 抽象工厂)
<?php
// 配置系统 - 结合两种模式
interface DatabaseConnection {
public function connect(): void;
public function query(string $sql): array;
}
interface CacheSystem {
public function set(string $key, $value): void;
public function get(string $key);
}
// 具体实现...
// 抽象工厂
interface InfrastructureFactory {
public function createDatabase(): DatabaseConnection;
public function createCache(): CacheSystem;
}
// 工厂方法(用于创建具体的工厂)
class InfrastructureFactoryManager {
public static function getFactory(string $environment): InfrastructureFactory {
return match ($environment) {
'development' => new DevelopmentInfrastructureFactory(),
'production' => new ProductionInfrastructureFactory(),
'testing' => new TestingInfrastructureFactory(),
default => throw new \InvalidArgumentException("Invalid environment")
};
}
}
实际项目建议
-
选择合适的模式:
- 产品种类固定但实现多变 → 工厂模式
- 产品族需要保持一致性 → 抽象工厂模式
-
避免过度设计:不要为简单场景使用复杂模式
-
结合依赖注入容器:现代 PHP 框架(如 Laravel、Symfony)都支持自动依赖注入,可以简化工厂实现
-
考虑扩展性:设计时预留扩展点,但不要过度抽象
工厂模式和抽象工厂模式是创建型设计模式的核心,它们能显著提高代码的可维护性和可扩展性,建议在实际项目中根据需求灵活运用。