PHP项目工厂模式与抽象工厂

wen PHP项目 1

本文目录导读:

PHP项目工厂模式与抽象工厂

  1. 工厂模式(Factory Pattern)
  2. 抽象工厂模式(Abstract Factory Pattern)
  3. 两者的核心区别
  4. 混合使用示例(工厂模式 + 抽象工厂)
  5. 实际项目建议

我会为你详细讲解 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")
        };
    }
}

实际项目建议

  1. 选择合适的模式

    • 产品种类固定但实现多变 → 工厂模式
    • 产品族需要保持一致性 → 抽象工厂模式
  2. 避免过度设计:不要为简单场景使用复杂模式

  3. 结合依赖注入容器:现代 PHP 框架(如 Laravel、Symfony)都支持自动依赖注入,可以简化工厂实现

  4. 考虑扩展性:设计时预留扩展点,但不要过度抽象

工厂模式和抽象工厂模式是创建型设计模式的核心,它们能显著提高代码的可维护性和可扩展性,建议在实际项目中根据需求灵活运用。

抱歉,评论功能暂时关闭!