首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 設計模式:工廠模式封裝物件建立邏輯

     編輯:PHP 綜合知識

工廠模式:將物件建立過程封裝,達成鬆耦合與擴展性

工廠模式 是創建型模式核心,透過統一介面建立物件,隱藏具體建立邏輯 (參數計算、子類選擇、依賴注入)。本文實作簡單工廠、工廠方法、抽象工廠三種變體。

一、簡單工廠

單一類別根據參數決定建立何種物件。非 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 主題家族

最佳實踐

  • ✅ 工廠方法回傳介面而非具體類別
  • ✅ 使用型別提示強制介面契約
  • ✅ 將建立邏輯從業務代碼移至工廠
  • ✅ 配合 DI 容器管理工廠本身
  • ⚠️ 避免工廠過度龐大 (單一職責)
  • ⚠️ 簡單情況優先考慮簡單工廠或直接 new
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved