工廠模式 (Factory)

在 Design Pattern 中,工廠模式(Factory) 基本的理念是建構一套完整工廠鍊,可以用來生產各種類別品項。

例如,建構資料庫工廠,可以用來產生 mysql, mongodb, redis…. 等物件。

對於使用者而言,他只需要在初始化工廠時,指定要生產的是什麼,

後續在操作資料庫的行為,都會一致。

例如,我們今天使用的是 mysql,如果改天要換成 pgsql ,只需要更改初始化的設定即可。

針對工廠模式,可以實作的方式很多,分別有以下幾種:

簡單工廠

首先,說明簡單工廠的實作,這裡用 Laravel 的 ORM 作為例子,

在建立資料庫連線時,資料庫的 Factory 會依照設定使用的資料庫類型來建立連線,

實作方式例如:

<?php
class ConnectionFactory
{

    protected $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }
    ...


    /**
     * Create a connector instance based on the configuration.
     *
     * @param  array  $config
     * @return \Illuminate\Database\Connectors\ConnectorInterface
     *
     * @throws \InvalidArgumentException
     */
    public function createConnector(array $config)
    {
        if (! isset($config['driver'])) {
            throw new InvalidArgumentException('A driver must be specified.');
        }

        if ($this->container->bound($key = "db.connector.{$config['driver']}")) {
            return $this->container->make($key);
        }

        switch ($config['driver']) {
            case 'mysql':
                return new MySqlConnector;
            case 'pgsql':
                return new PostgresConnector;
            case 'sqlite':
                return new SQLiteConnector;
            case 'sqlsrv':
                return new SqlServerConnector;
        }

        throw new InvalidArgumentException("Unsupported driver [{$config['driver']}]");
    }

    /**
     * Create a new connection instance.
     *
     * @param  string   $driver
     * @param  \PDO|\Closure     $connection
     * @param  string   $database
     * @param  string   $prefix
     * @param  array    $config
     * @return \Illuminate\Database\Connection
     *
     * @throws \InvalidArgumentException
     */
    protected function createConnection($driver, $connection, $database, $prefix = '', array $config = [])
    {
        if ($resolver = Connection::getResolver($driver)) {
            return $resolver($connection, $database, $prefix, $config);
        }

        switch ($driver) {
            case 'mysql':
                return new MySqlConnection($connection, $database, $prefix, $config);
            case 'pgsql':
                return new PostgresConnection($connection, $database, $prefix, $config);
            case 'sqlite':
                return new SQLiteConnection($connection, $database, $prefix, $config);
            case 'sqlsrv':
                return new SqlServerConnection($connection, $database, $prefix, $config);
        }

        throw new InvalidArgumentException("Unsupported driver [{$driver}]");
    }
}

通常簡單模式,最常被提及的就是會違反 開放封閉原則 Open-Closed Principle(OCP)

工廠抽象化

工廠抽象的方式,可以透過 Abstract 或 Interface 來建構工廠,實作過程僅作描述,不實作邏輯。邏輯會保留到各個類別繼承或implements 之後,強制實作。