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

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

工厂模式

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

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

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

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

以下是我的目录结构:

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

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

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

文件: tests/bootstrap.php

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

$loader = new \Composer\Autoload\ClassLoader();

$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/DesignPatterns\FactoryMode\DB\MysqlDrive.php

namespace Dudulu\DesignPatterns\FactoryMode;

use Dudulu\DesignPatterns\DB\MysqlDrive;

/**

* Class Factory

* @package Dudulu\DesignPatterns\FactoryMode

*/

class Factory

{

/**

* @return MysqlDrive

*/

public static function database()

{

return new MysqlDrive();

}

}

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

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

namespace Dudulu\DesignPatterns\DB\Interfaces;

/**

* Interface DriveInterface

* @package Dudulu\DesignPatterns\DB\Interfaces

*/

interface DriveInterface

{

/**

* @return mixed

*/

public function connection();

}

普通模式

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

include_once "../bootstrap.php";

use Dudulu\DesignPatterns\DB\MysqlDrive;

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 Dudulu\DesignPatterns\FactoryMode;

use Dudulu\DesignPatterns\DB\MysqlDrive;

/**

* Class Factory

* @package Dudulu\DesignPatterns\FactoryMode

*/

class Factory

{

/**

* @return MysqlDrive

*/

public static function database()

{

return new MysqlDrive();

}

}

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

文件: tests/DesignPattens/FactoryTest.php

include_once "../bootstrap.php";

use Dudulu\DesignPatterns\FactoryMode\Factory;

class FactoryTest extends PHPUnit_Framework_TestCase {

public function testConnection()

{

$db = Factory::database();

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

}

}

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

单例模式

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

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

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

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

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

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

namespace Dudulu\DesignPatterns\SingletonMode;

use Dudulu\DesignPatterns\DB\Interfaces\DriveInterface;

/**

* Class SingletonDB

* @package Dudulu\DesignPatterns\SingletonMode

*/

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 Dudulu\DesignPatterns\SingletonMode\SingletonDB;

/**

* 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 Dudulu\DesignPatterns\RegisterMode;

/**

* Class Register

* @package Dudulu\DesignPatterns\RegisterMode

*/

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 Dudulu\DesignPatterns\DB;

use Dudulu\DesignPatterns\DB\Interfaces\DriveInterface;

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 Dudulu\DesignPatterns\RegisterMode\Register;

/**

* @return DemoDB

*/

public static function testDb()

{

$db = DemoDB::getInstance();

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

return $db;

}

最后咱们验证一下:

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

include_once "../bootstrap.php";

use Dudulu\DesignPatterns\RegisterMode\Register;

use Dudulu\DesignPatterns\DB\DemoDB;

/**

* 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⌒ / /

|ヽ  |  ノ/

\トー仝ーイ

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

php工厂模式和单例模式,php 设计模式之工厂模式、单例模式、注册树模式相关推荐

  1. 【laravel】门面:重载、延迟静态绑定、注册树模式、外观模式、Mockery

    laravel中路由.缓存等常常有Rote::get().Cache::get()这样的写法,引入对应门面类就可以使用所定义方法,然而打开所引用门面类,并没有这些方法呀,那么它是怎样实现的呢?以及为何 ...

  2. 基础设计模式:单例模式+工厂模式+注册树模式

    单例模式: 通过提供自身共享实例的访问,单例设计模式用于限制特定对象只能被创建一次. 使用场景: 一般数据库实例都会用单例模式 实现: 单例设计模式就是要一个类只能实例化一个对象. 要想让一个类只能实 ...

  3. 慕课网----大话PHP设计模式 三(三种基本设计模式-工厂模式,单例模式,注册树模式)

    1)工厂模式: 工厂方法或者类生成对象,而不是代码中直接new 多用来生成对象 好处.如果很多个文件都使用了这个类的话,如果修改需要去每个文件下都进行修改,而使用工厂模式的话,则只用在类里面修改创建方 ...

  4. php注册树模式,PHP三种基本设计模式(工厂模式、单例模式、注册树模式)

    一.工厂设计模式 index.php $db = IMooc\Factory::createDatabase(); 使用工厂类的静态方法直接创建一个dababase对象,当类名发生修改时,在工厂里修改 ...

  5. php注册树模式,php基础设计模式大全(注册树模式、工厂模式、单列模式)

    废话不多说了,先给大家介绍注册树模式然后介绍工厂模式最后给大家介绍单列模式,本文写的很详细,一起来学习吧. php注册树模式 什么是注册树模式? 注册树模式当然也叫注册模式,注册器模式.之所以我在这里 ...

  6. php 注册树,php常用设计模式(单例,工厂,注册树模式)

    单例模式 实例 /医院 * 单例模式 */ class Single { private static $instance = null; // 不允许实例化 private function __c ...

  7. php注册树模式,PHP设计模式之详记注册树模式

    一.什么是注册树模式 注册树模式又叫注册模式.注册器模式.注册树模式是将经常使用到的对象实例挂到一颗全局的树上,需要使用时从数树上取出即可. 举个栗子:有一个空的工具箱.需要维修东西,因此买了扳手和螺 ...

  8. php 注册树,php设计模式-注册树模式

    注册树模式概念 注册树模式也叫注册模式或注册器模式.注册树模式将对象实例注册到一棵全局的对象树上,需要的时候从对象树上获取即可. 注册树模式优点 单例模式创建唯一对象的过程本身还有一种判断,即判断对象 ...

  9. php注册树模式,php设计模式-注册树模式

    注册树模式概念 注册树模式也叫注册模式或注册器模式.注册树模式将对象实例注册到一棵全局的对象树上,需要的时候从对象树上获取即可. 注册树模式优点 单例模式创建唯一对象的过程本身还有一种判断,即判断对象 ...

最新文章

  1. jquery validate使用
  2. C++对象模型2——编译器生成构造函数的几种情况
  3. coeforces 665D D. Simple Subset(最大团orsb题)
  4. 047_输出一下byte的所有值
  5. linux dip 命令详解
  6. HailStone序列
  7. C/Cpp / STL / 各个实现版本的说明
  8. Jar Hell变得轻松–用jHades揭开类路径的神秘面纱
  9. 【总结】Qt+Mysql5.5中文乱码解决
  10. linux 运行有道词典,Ubuntu中使用有道词典
  11. 印度影星沙鲁克-罕简介
  12. 几种非接触涂层测厚方法原理对比
  13. java日志,需要知道的几件事(commons-logging,log4j,slf4j,logback)
  14. sqlite自动转mysql,Sqlite数据库转换为mysql工具SqliteToMysql使用教程
  15. android 应用置顶到最前端_Android 将后台应用切换到前台
  16. Win10双击调试 转载 http://blog.csdn.net/sagittarius_warrior/article/details/51305046
  17. Packet Tracer 5.0 汉化包
  18. ROS wiki learn 整理 1
  19. 如何学习symbian(转)
  20. 32位和64位系统的区别及如何选择?

热门文章

  1. Snap svg:路径变换和相交计算
  2. HEC-RAS二维溃坝洪水模拟(尾矿库)
  3. wince的调试串口作为普通串口使用
  4. 双稳态电路的两个稳定状态是什么_从双稳态到双“更”稳态 ——叶芳伟课题组在拓扑光子学研究方向上取得新进展...
  5. php查询文件名,php怎么查询文件名
  6. 计算机用户win7修改不,Win7电脑时间改不了的解决方法
  7. python教程闭包_Python教程 闭包的特性
  8. C语言程序设计(代码+知识点)
  9. 【转】VS编译环境命令窗口中的命令
  10. ELK Stack 与 Elastic Stack 的异同点