php设计模式(七)使用反射来优化抽象工厂模式

简单工厂的核心是 switch 或者 if 判断;
但是简单工厂配合抽象工厂的时候;
工厂里面的每个用来实例化产品的方法都需要 switch ;
这就显的重复了;
这时候我们可以使用反射来优化;

结构

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

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

示例

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

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

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithReflection;

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

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

Article.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithReflection;

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

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

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

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithReflection;

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

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

MySQLArticle.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithReflection;

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

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

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

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithReflection;

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

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

SQLiteArticle.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithReflection;

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

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

产品部分没有什么变化;

配置项也一样;
config.php

<?php

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

核心就是反射部分;
Factory.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithReflection;

use ReflectionClass;
use ReflectionException;

class Factory
{
    /**
     * 数据库
     *
     * @var string
     */
    public $db = 'MySQL';

    /**
     * 产品类的命名空间
     *
     * @var string
     */
    public $namespace = 'Baijunyao\DesignPatterns\AbstractFactoryWithReflection\\';

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

    /**
     * 创建 User 产品
     *
     * @return MySQLUser|SQLiteUser
     */
    public function createUser()
    {
        $className = $this->namespace . $this->db . 'User';
        try {
            $class = new ReflectionClass($className);
            $user = $class->newInstance();
        } catch (ReflectionException $Exception) {
            throw new \InvalidArgumentException('暂不支持的数据库类型');
        }
        return $user;
    }

    /**
     * 创建 Article 产品
     *
     * @return MySQLArticle|SQLiteArticle
     */
    public function createArticle()
    {
        $className = $this->namespace . $this->db . 'Article';
        try {
            $class = new ReflectionClass($className);
            $article = $class->newInstance();
        } catch (ReflectionException $Exception) {
            throw new \InvalidArgumentException('暂不支持的数据库类型');
        }
        return $article;
    }
}

运行;
index.php

<?php

namespace Baijunyao\DesignPatterns\AbstractFactoryWithReflection;

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

/**
 * 客户端
 *
 * Class Client
 * @package Baijunyao\DesignPatterns\AbstractFactoryWithReflection
 */
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();

当我们需要支持更多的数据库的时候;
比如说 PostgreSQL ;
我们只需要新建 PostgreSQLUser 和 PostgreSQLArticle ;
这就符合开闭原则了;
可以方便的扩展且不需要修改 createUser 方法;

over;
工厂相关的设计模式终于告一段落;

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

简单工厂优化抽象工厂

白俊遥博客
请先登录后发表评论
  • 最新评论
  • 总共5条评论
白俊遥博客

孤城浪子:这里的类都没有构造函数所以直接就new了,如果有构造函数是不是还应该加个依赖注入的功能呢。

2018-09-20 18:38:18 回复

白俊遥博客

Summer:很好

2018-08-28 09:43:56 回复

白俊遥博客

时光机:很好

2018-08-18 02:46:44 回复

白俊遥博客

for_bug_Do_first:&lgt;script&rgt;alert(123123)&lgt;script/&rgt;

2018-08-17 18:10:43 回复

白俊遥博客

for_bug_Do_first:alert('11111')

2018-08-17 18:09:27 回复