php设计模式(六)使用简单工厂来优化抽象工厂模式

抽象工厂模式中每增加一类产品都要改动全部的工厂;
这个工厂就是我们痛苦的源泉了;
这时候可以使用简单工厂来优化抽象工厂;

结构

多个 interface 或者 abstract 产品父类;
多个实现 interface 或者继承 abstract 的具体产品类;

1个工厂;
工厂类里面有多个方法分别实例化不同的具体产品类;

示例

产品部分跟抽象工厂是一样的;

先创建 User 和 Article 产品 interface ;
User.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

/**
 * User 产品接口
 *
 * Interface User
 * @package Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory
 */
interface User
{
    /**
     * 新增
     *
     * @return mixed
     */
    public function insert();

    /**
     * 查询
     *
     * @return mixed
     */
    public function select();
}

Article.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

/**
 * Article 产品接口
 *
 * Interface Article
 * @package Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory
 */
interface Article
{
    /**
     * 新增
     *
     * @return mixed
     */
    public function insert();

    /**
     * 查询
     *
     * @return mixed
     */
    public function select();
}

然后创建对应的 MySQL 产品;
MySQLUser.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

/**
 * 应用于 MySQL 的 User
 *
 * Class MySQLUser
 * @package Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory
 */
class MySQLUser implements User
{
    /**
     * 新增
     */
    public function insert()
    {
        echo '向 MySQL 数据库中插入 User';
    }

    /**
     * 查询
     */
    public function select()
    {
        echo '从 MySQL 数据库中查询 User';
    }
}

MySQLArticle.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

/**
 * 应用于 MySQL 的 Article
 *
 * Class MySQLArticle
 * @package Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory
 */
class MySQLArticle implements Article
{
    /**
     * 新增
     */
    public function insert()
    {
        echo '向 MySQL 数据库中插入 Article';
    }

    /**
     * 查询
     */
    public function select()
    {
        echo '从 MySQL 数据库中查询 Article';
    }
}

然后创建对应的 SQLite 产品;
SQLiteUser.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

/**
 * 适用于 SQLite 的 User
 *
 * Class SQLiteUser
 * @package Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory
 */
class SQLiteUser implements User
{
    /**
     * 新增
     */
    public function insert()
    {
        echo '向SQLite数据库中插入 User';
    }

    /**
     * 查询
     */
    public function select()
    {
        echo '从SQLite数据库中查询 User';
    }
}

SQLiteArticle.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

/**
 * 适用于 SQLite 的 Article
 *
 * Class SQLiteArticle
 * @package Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory
 */
class SQLiteArticle implements Article
{
    /**
     * 新增
     *
     * @return mixed|void
     */
    public function insert()
    {
        echo '向 SQLite 数据库中插入 Article';
    }

    /**
     * 查询
     *
     * @return mixed|void
     */
    public function select()
    {
        echo '从 SQLite 数据库中查询 Article';
    }
}

产品部分没有什么变化;
那工厂就是优化的关键了;
Factory.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

class Factory
{
    public $db = 'MySQL';

    /**
     * 创建 User 产品
     *
     * @return MySQLUser|SQLiteUser
     */
    public function createUser()
    {
        switch ($this->db) {
            case 'MySQL':
                $user =  new MySQLUser();
                break;
            case 'SQLite':
                $user =  new SQLiteUser();
                break;
            default:
                throw new \InvalidArgumentException('暂不支持的数据库类型');
        }
        return $user;
    }

    /**
     * 创建 Article 产品
     *
     * @return MySQLArticle|SQLiteArticle
     */
    public function createArticle()
    {
        switch ($this->db) {
            case 'MySQL':
                $article =  new MySQLArticle();
                break;
            case 'SQLite':
                $article =  new SQLiteArticle();
                break;
            default:
                throw new \InvalidArgumentException('暂不支持的数据库类型');
        }
        return $article;
    }
}

运行;
index.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

require __DIR__.'/../vendor/autoload.php';

/**
 * 客户端
 *
 * Class Client
 * @package Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory
 */
class Client
{
    /**
     * 运行
     */
    public function run()
    {
        $factory = new Factory();

        // 创建 user
        $user = $factory->createUser();
        $user->insert();
        echo '<br>';
        $user->select();

        echo '<hr>';

        // 创建 article
        $article = $factory->createArticle();
        $article->insert();
        echo '<br>';
        $article->select();
    }
}

$client = new Client();
$client->run();

不过 Factory 中把 db 属性固定为 MySQL 了;
想换数据库类型还需要手动修改 db ;
我们还可以写个配置文件;
从配置文件中读取;
这样就不用改动 Factory 文件了;
config.php

<?php

return [
    'driver' => 'MySQL'
];

Factory.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithSimpleFactory;

class Factory
{
    public $db = 'MySQL';

    /**
     * Factory constructor.
     */
    public function __construct()
    {
        /**
         * 从配置项中获取 driver
         */
        $config = include 'config.php';
        $this->db = $config['driver'];
    }

    /**
     * 创建 User 产品
     *
     * @return MySQLUser|SQLiteUser
     */
    public function createUser()
    {
        switch ($this->db) {
            case 'MySQL':
                $user =  new MySQLUser();
                break;
            case 'SQLite':
                $user =  new SQLiteUser();
                break;
            default:
                throw new \InvalidArgumentException('暂不支持的数据库类型');
        }
        return $user;
    }

    /**
     * 创建 Article 产品
     *
     * @return MySQLArticle|SQLiteArticle
     */
    public function createArticle()
    {
        switch ($this->db) {
            case 'MySQL':
                $article =  new MySQLArticle();
                break;
            case 'SQLite':
                $article =  new SQLiteArticle();
                break;
            default:
                throw new \InvalidArgumentException('暂不支持的数据库类型');
        }
        return $article;
    }
}

虽然有了简单工厂可以少建一堆工厂了;
但是这里面的多个 switch 明显是有点重复的;
这呼吸起来还是有点痛;
下篇文章我们用反射优化抽象工厂进一步减轻这种痛;

github示例:https://github.com/baijunyao/design-patterns/tree/master/AbstractFactoryWithSimpleFactory

白俊遥博客
请先登录后发表评论
  • latest comments
  • 总共6条评论
白俊遥博客

卡牌 :嗯

2018-08-15 21:25:34 回复

白俊遥博客

小小強 :学习了。学习了。

2018-08-15 09:21:06 回复

白俊遥博客

弘毅51hongyi.cn :最后一张图是怎么弄的

2018-08-14 22:19:04 回复

白俊遥博客 白俊遥博客

云淡风晴 :phpstorm 中在目录上按 command+alt+shift+u 快捷键

2018-09-02 22:47:51 回复

白俊遥博客

Cccc沫子 :的

2018-08-13 15:42:55 回复

白俊遥博客

Morphine :不错。学习了。

2018-08-13 13:17:39 回复