资讯专栏INFORMATION COLUMN

php 设计模式之工厂模式、单例模式、注册树模式

liangzai_cool / 2372人阅读

摘要:的设计模式有很多种,本文取最简单的三种模式工厂模式单例模式和注册树模式进行简单的讲解。文件创建完后,咱们回到单元测试文件文件再执行一下单元测试命令发现,也能返回成功,这样的话我们就能很方便的修改任何驱动了。

php 设计模式之工厂模式、单例模式、注册树模式

在软件工程中,创建型设计模式承担着对象创建的职责,尝试创建适合程序上下文的对象,对象创建设计模式的产生是由于软件工程设计的问题,具体说是向设计中增加复杂度,创建型设计模式解决了程序设计中对象创建的问题。PHP的设计模式有很多种,本文取最简单的三种模式: 工厂模式、单例模式和注册树模式进行简单的讲解。

工厂模式

用工厂方法或者类生成对象,而不是代码中直接使用 new 关键字

比如咱们要做一个连接数据库的操作,平时都是用mysql。那突然有一天mysql收费了,咋办?那我们就用Sqlite作来数据库。如果以传统的方式创建一个数据库连接类的话是需要使用关键字new MysqlDrive()把这个数据库实例化,一旦数据库变更成的话就需要把所有的new MysqlDrive()变更成new SqliteDrive() 这样替换比较麻烦,并且还容易出错。所以,下面的工厂模式可以很好的解决这一问题。

废话不多说,演示一遍就明白了

先看一下目录结构吧本文演示的全部是遵循PSR-4的编码规范,当然,是在vendor/目录下,如果没有请自己行执行命令composer dumpatuoload 如果您没有安装composer那就请看下面文章:

《集成 Composer 包依赖管理》

以下是我的目录结构:

自动忽略DependencyInjection 跟HttpFoundation目录,这是我计划下次写的东西,嘻嘻...


先看看主要文件的代码吧:

tests/这个目录是为了让咱们方便测试的目录,也就是单元测试目录

文件: tests/bootstrap.php

include_once __DIR__."/../../../composer/ClassLoader.php";

$loader = new ComposerAutoloadClassLoader();

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

$classMaps = [
    "Dudulu" => [$vendorDir."/src/"]
];

foreach ($classMaps as $namespace => $path) {
    $loader->setPsr4($namespace, $path);
}

$loader->register(true);

咱们需要测试的驱动类MysqlDerive.php

文件: src/DesignPatternsFactoryModeDBMysqlDrive.php

namespace DuduluDesignPatternsFactoryMode;

use DuduluDesignPatternsDBMysqlDrive;

/**
 * Class Factory
 * @package DuduluDesignPatternsFactoryMode
 */
class Factory
{

    /**
     * @return MysqlDrive
     */
    public static function database()
    {
        return new MysqlDrive();
    }
}

为了强制让每种驱动都要有一个连接方式,所以我们需要一个Interface。

文件: src/DesignPatterns/DB/Interfaces/DriveInterface.php

namespace DuduluDesignPatternsDBInterfaces;


/**
 * Interface DriveInterface
 * @package DuduluDesignPatternsDBInterfaces
 */
interface DriveInterface
{
    /**
     * @return mixed
     */
    public function connection();
}
普通模式

先看一个普通demo,直接实例化MysqlDrive对象

include_once "../bootstrap.php";

use DuduluDesignPatternsDBMysqlDrive;

class FactoryTest extends PHPUnit_Framework_TestCase {

    public function testConnection()
    {
        $db = new MysqlDrive();

        $this->assertEquals(true, $db->connection());
    }
}

进入src/tests/DesignPattens目录.

命令行执行: phpunit FactoryTest.php可以发现这样是好使的...

工厂模式

工厂模式 是一种类,它具有为您创建对象的某些方法。您可以使用工厂类创建对象,而不直接使用 new。这样,如果您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的所有代码会自动更改。

首先咱们先创建一个Factory.php作为工厂类,然后里边实现一个静态方法对相数据库驱动进行实例化。

文件: src/DesignPatterns/FactoryMode/Factory.php

namespace DuduluDesignPatternsFactoryMode;

use DuduluDesignPatternsDBMysqlDrive;

/**
 * Class Factory
 * @package DuduluDesignPatternsFactoryMode
 */
class Factory
{

    /**
     * @return MysqlDrive
     */
    public static function database()
    {
        return new MysqlDrive();
    }
}

创建完后,咱们回到单元测试文件FactoryTest.php

文件: tests/DesignPattens/FactoryTest.php

include_once "../bootstrap.php";

use DuduluDesignPatternsFactoryModeFactory;

class FactoryTest extends PHPUnit_Framework_TestCase {

    public function testConnection()
    {
        $db = Factory::database();

        $this->assertEquals(true, $db->connection());
    }
}

再执行一下单元测试命令发现,也能返回成功,这样的话我们就能很方便的修改任何驱动了。如果我们从mysql换到sqlite了,那么,咱们主要的代码都不需要更变,只要在Factory.phpconnection方法的边接方式修改完就好了,非常方便。

单例模式

使某个类的对象仅允许创建一个

某些应用程序资源是独占的,因为有且只有一个此类型的资源。比如,数据库的连接的独占。希望在应用程序中共享数据库连接,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。

比如咱们连接数据库时,如果不使用单例模式,多个地方都对数据类进行了实例化,那么这样会造能很多资源浪费,为了解决这问题,对于数据库类我们只需要实例化一次,后面再次调用它是如果已经实例化,那就直接返回。

来,我们拿一个类来玩一玩...

文件: src/DesignPatterns/SingletonMode/SingletonDB.php

我们创建这个类,然后将构造方法私有化,这样的话我们就无法使用new关键字对这个类进行实例化了。

namespace DuduluDesignPatternsSingletonMode;


use DuduluDesignPatternsDBInterfacesDriveInterface;

/**
 * Class SingletonDB
 * @package DuduluDesignPatternsSingletonMode
 */
class SingletonDB implements DriveInterface
{

    /**
     * SingletonDB constructor.
     */
    private function __construct()
    {

    }

    /**
     * @return bool
     */
    public function connection()
    {
        return true;
    }
}

那么我们要如何使用这个对象呢?我们需要一个受保护的成员和一个静态方法:

    /**
     * @var SingletonDB
     */
    protected static $db;
    
    /**
     * @return SingletonDB
     */
    public static function getInstance()
    {
        if (self::$db) {
            return self::$db;
        }
        self::$db = new self();
        return self::$db;
    }

这个方法很好理解,简单意思就是如果当前属性已经被设置过了,那就不再进行实例化,而是直接返回,否则实例化当前对象并返回。

与测试上面的方法一样,测玩玩...

创建测试的文件: tests/DesignPattens/SingletonDBTest.php

include_once "../bootstrap.php";

use DuduluDesignPatternsSingletonModeSingletonDB;

/**
 * Class SingletonDBTest
 */
class SingletonDBTest extends PHPUnit_Framework_TestCase
{
    /**
     * @return void
     */
    public function testConnection()
    {
        $db = SingletonDB::getInstance();

        $this->assertEquals(true, $db->connection());
    }
}

执行命令: phpunit SingletonDBTest.php 发现也是可以执行成功的。

如果不信的话,你可以试试多执行几次SingletonDB::getInstance(); 然后在 getInstance() 方法体里做一个计数器,看看它实例化过几次。

注册树模式

主要用来解决全局共享和交换对象

这个也很好理解,因为我们在框架中经常用到。

注册树模式当然也叫注册模式,注册器模式。之所以我在这里矫情一下它的名称,是因为我感觉注册树这个名称更容易让人理解。注册树模式通过将对象实例注册到一棵全局的对象树上,需要的时候从对象树上采摘的模式设计方法。

咱们结合工厂模式及单例模式做一个小例子:

创建文件: src/DesignPatterns/RegisterMode/Register.php

namespace DuduluDesignPatternsRegisterMode;


/**
 * Class Register
 * @package DuduluDesignPatternsRegisterMode
 */
class Register
{
    /**
     * @var array
     */
    protected static $classMaps = [];

    /**
     * @param $alias
     * @param $class
     * @return void
     */
    public static function set($alias, $class )
    {
        self::$classMaps[$alias] = $class;
    }

    /**
     * @param $alias
     * @return mixed
     */
    public static function get($alias )
    {
        return self::$classMaps[$alias];
    }
}

然后创建一个单例模式的DB类DemoDB.php:

文件: src/DesignPatterns/DB/DemoDB.php

namespace DuduluDesignPatternsDB;


use DuduluDesignPatternsDBInterfacesDriveInterface;

class DemoDB implements DriveInterface
{
    /**
     * @var DemoDB
     */
    protected static $db;

    /**
     * SingletonDB constructor.
     */
    private function __construct()
    {

    }

    /**
     * @return DemoDB
     */
    public static function getInstance()
    {
        if (self::$db) {
            return self::$db;
        }
        self::$db = new self();
        return self::$db;
    }

    /**
     * @return bool
     */
    public function connection()
    {
        return true;
    }
}

再工厂模式文件上加入注册方式代码:

文件: src/DesignPatterns/FactoryMode/Factory.php

    use DuduluDesignPatternsRegisterModeRegister;

    /**
     * @return DemoDB
     */
    public static function testDb()
    {
        $db = DemoDB::getInstance();

        Register::set("DB", $db);

        return $db;
    }

最后咱们验证一下:

tests/目录下创建RegisterTest.php文件

include_once "../bootstrap.php";

use DuduluDesignPatternsRegisterModeRegister;
use DuduluDesignPatternsDBDemoDB;

/**
 * Class RegisterTest
 */
class RegisterTest extends PHPUnit_Framework_TestCase
{
    /**
     * @return void
     */
    public function testConnection()
    {
        Register::set("DB", DemoDB::getInstance());

        $db = Register::get("DB");

        $this->assertEquals(true, $db->connection());
    }
}

OK 走一个phpunit RegisterTest.php

返回OK,好棒好棒...☆〜(ゝ。∂)

  __
  / )))    _
`/ イ~   (((ヽ
(  ノ      ̄Y\
| (\ ∧_∧ | )
ヽ ヽ`( `o´ )/ノ/
 \ | ⌒Y⌒ / /
  |ヽ  |  ノ/
  \トー仝ーイ
   |

GitHub: https://github.com/icowan/dudulu

如果有时间,下次我再写些关于其他设计模式的文章...

原文地址: 设计模式之工厂模式、单例模式、注册树模式
欢迎关注我站点: LatteCake
欢迎关注公众号: 聪聪实验室

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30285.html

相关文章

  • php设计模式工厂模式单例模式注册模式

    摘要:一工厂模式工厂方法或类中生成对象,而不是在代码中直接优点将某个常用类,多个地方需要时,使用工厂模式,方便类的扩展与维护文件目录正常实例化类获取单例模式的类将实例化后的类注册到全局注册树中外部调用得到对象获取全局注册树中的对象卸载全局注册树中 一、工厂模式:工厂方法或类中生成对象,而不是在代码中直接 new 优点:将某个常用类,多个地方需要 new 时,使用工厂模式,方便类的扩展与维护文...

    孙吉亮 评论0 收藏0
  • php设计模式

    摘要:我们今天也来做一个万能遥控器设计模式适配器模式将一个类的接口转换成客户希望的另外一个接口。今天要介绍的仍然是创建型设计模式的一种建造者模式。设计模式的理论知识固然重要,但 计算机程序的思维逻辑 (54) - 剖析 Collections - 设计模式 上节我们提到,类 Collections 中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了...

    Dionysus_go 评论0 收藏0
  • php设计模式

    摘要:我们今天也来做一个万能遥控器设计模式适配器模式将一个类的接口转换成客户希望的另外一个接口。今天要介绍的仍然是创建型设计模式的一种建造者模式。设计模式的理论知识固然重要,但 计算机程序的思维逻辑 (54) - 剖析 Collections - 设计模式 上节我们提到,类 Collections 中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了...

    vspiders 评论0 收藏0
  • php的三种主要设计模式

    摘要:很多接触的框架就是基于各种模式设计形成的。在所有模式设计中,有三种基础设计模式,单例模式,工厂模式,注册树模式,其他模式往往基于这几种模式,今天带来的是单例模式。工厂模式更多考虑的是扩展维护的问题。 (非原创) 一.单例模式 模式设计是什么?初学者一开始会被这高大上的名称给唬住。而对于有丰富编程经验的老鸟来说,模式设计又是无处不在。很多接触的框架就是基于各种模式设计形成的。 简单说,在...

    gityuan 评论0 收藏0
  • Javag工程师成神路(2019正式版)

    摘要:结构型模式适配器模式桥接模式装饰模式组合模式外观模式享元模式代理模式。行为型模式模版方法模式命令模式迭代器模式观察者模式中介者模式备忘录模式解释器模式模式状态模式策略模式职责链模式责任链模式访问者模式。 主要版本 更新时间 备注 v1.0 2015-08-01 首次发布 v1.1 2018-03-12 增加新技术知识、完善知识体系 v2.0 2019-02-19 结构...

    Olivia 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<