Yii2设计模式——注册树模式
应用举例
在Yii.php中:
<?php
class ServiceLocator extends Component
{
//保存实例化的对象,每个对象都是单例,且有唯一string类型的ID做区分
private $_components = [];
//保存设置的对象或者其定义,用于实例化
private $_definitions = [];
//将对象ID作为ServiceLocator的属性,可通过$serviceLocator->{ID}直接获取
public function __get($name)
{
if ($this->has($name)) {
return $this->get($name);
}
return parent::__get($name);
}
//检验是否有属性$name
public function __isset($name)
{
if ($this->has($name)) {
return true;
}
return parent::__isset($name);
}
//检验是否有对象$id
public function has($id, $checkInstance = false)
{
return $checkInstance ? isset($this->_components[$id]) : isset($this->_definitions[$id]);
}
//获取一个对象$id
public function get($id, $throwException = true)
{
//已经实例化的,直接返回
if (isset($this->_components[$id])) {
return $this->_components[$id];
}
//有该对象的定义,且定义已经是一个对象,设置$_components并直接返回
if (isset($this->_definitions[$id])) {
$definition = $this->_definitions[$id];
if (is_object($definition) && !$definition instanceof Closure) {
return $this->_components[$id] = $definition;
}
//有定义但不是现成对象,则交给DI Container去实例化,并且设置$_components
return $this->_components[$id] = Yii::createObject($definition);
} elseif ($throwException) {
throw new InvalidConfigException("Unknown component ID: $id");
}
return null;
}
//设置、存放一个对象
public function set($id, $definition)
{
unset($this->_components[$id]);
if ($definition === null) {
unset($this->_definitions[$id]);
return;
}
//如果$definition是对象或者类名或者callable,则注册到$_definitions中
if (is_object($definition) || is_callable($definition, true)) {
// an object, a class name, or a PHP callable
$this->_definitions[$id] = $definition;
} elseif (is_array($definition)) { //如果是带'class'的配置数组,也注册到$_definitions中
// a configuration array
if (isset($definition['class'])) {
$this->_definitions[$id] = $definition;
} else {
throw new InvalidConfigException("The configuration for the \"$id\" component must contain a \"class\" element.");
}
} else {
throw new InvalidConfigException("Unexpected configuration type for the \"$id\" component: " . gettype($definition));
}
}
//清楚注册的对象
public function clear($id)
{
unset($this->_definitions[$id], $this->_components[$id]);
}
}
这里用到了注册树。
注册树模式
注册树模式(Registry Pattern)又叫注册模式、注册器模式。注册树模式通过将对象实例注册到一棵全局的对象树上,需要的时候从对象树上采摘的模式设计方法。
为什么要采用注册树模式?
单例模式在整个项目中创建唯一实例的问题;工厂模式封装了对象的创建方式(工厂方法——用一个抽象方法,抽象工厂——用一簇抽象方法),使得不必总用new关键词去获取对象;创建者模式则是分步骤的创建实例的各个部分;在Yii2中则通过依赖注入容器DI去获取实例...
这些方法实际上都是解决一个问题——如何合理的产生一个对象。但对象既然已经产生出来了,怎么方便的调用这些对象呢?我们在项目内部建立的对象好像散兵游勇一样,不方便统筹管理安排啊。因而注册数模式应运而生。不管你是何种方式产生的对象,都给我“插到”注册树上。我用某个对象的时候,直接从注册树上去取一下就好了,是不是非常方便?注册时模式还为其他模式提供了一种非常好的想法。
代码实现
看看注册树模式的实现:
class Register
{
//存放对象的数组
protected static $objects;
/**
* 存放一个对象
* @param $alias
* @param $object
*/
public static function set($alias,$object)
{
self::$objects[$alias] = $object;
}
/**
* 获取一个对象
* @param $alias
* @return mixed
*/
public static function get($alias)
{
return self::$objects[$alias];
}
/**
* 销毁一个对象
* @param $alias
*/
public static function _unset($alias)
{
unset(self::$objects[$alias]);
}
}
注册树模式很类似服务定位器模式,优点是集中管理,使用方便。缺点是隐藏了对象和对象之间的依赖关系。
Yii2的注册树模式
PHP注册树模式主要用于创建对象的时候将我们的对象与相应的变量进行绑定,从这个角度上说,Yii2的Service Locator和DI Container都用到注册树模式。这二者都在内部维护一个数组(key => value),value为对象或者对象定义,在获取时通过唯一的key来获取,如果是定义再去容器里面实例化一下。
Yii2设计模式——注册树模式的更多相关文章
- php基础设计模式 注册树模式、工厂模式、单列模式
废话不多说了,先给大家介绍注册树模式然后介绍工厂模式最后给大家介绍单列模式,本文写的很详细,一起来学习吧. php注册树模式 什么是注册树模式? 注册树模式当然也叫注册模式,注册器模式.之所以我在这里 ...
- php设计模式-注册树模式
php注册树模式 1.什么是注册树模式? 注册树模式通过将对象实例注册到全局对象树上,需要的时候将对象从全局对象树上取下来,就像小时候买糖葫芦一样,卖糖葫芦的将糖葫芦插在一个大的杆子上,人们买的时候就 ...
- php模式设计之 注册树模式
在前两篇单例模式和工厂模式后,终于迎来了最后一个基础的设计模式--注册树模式. 什么是注册树模式? 注册树模式当然也叫注册模式,注册器模式.之所以我在这里矫情一下它的名称,是因为我感觉注册树这个名称更 ...
- PHP设计模式笔记三:三种基本设计模式(工厂模式、单例模式、注册树模式) -- Rango韩老师 http://www.imooc.com/learn/236
一.工厂设计模式 index.php $db = IMooc\Factory::createDatabase(); 使用工厂类的静态方法直接创建一个dababase对象,当类名发生修改时,在工厂里修改 ...
- 2018/04/24 PHP 设计模式之注册树模式
之前学习了工厂模式和单例模式,明白了他们的意义. 但是我们在之后的使用中会发现一个问题,在新建一个实例的时候还是需要调用一个单例或者工厂,之后还是造成了代码和耦合和不好处理. 下面开始说一下: -- ...
- php设计模式之注册树模式
什么是注册树模式?[全局共享和交换对象] 注册树模式当然也叫注册模式,注册器模式.注册树模式通过将对象实例注册到一棵全局的对象树上,需要的时候从对象树上采摘的模式设计方法. 这让我想起了小时候买糖 ...
- PHP设计模式_注册树模式
通过注册树模式可以更加简单快捷的获取对象,在某个地方实例化了一个对象,可以将这个对象“保存”起来(放入可以全局使用的数组里),用的时候只需要提供 保存对象的时候 的那个标识即可,解决全局共享和交换对象 ...
- PHP模式设计之单例模式、工厂模式、注册树模式、适配器模式、观察者模式
php模式设计之单例模式 什么是单例模式? 单例模式是指在整个应用中只有一个实例对象的设计模式 为什么要用单例模式? php经常要链接数据库,如果在一个项目中频繁建立连接数据库,会造成服务器资源的很大 ...
- PHP 注册树模式
/** * 注册树模式 * 将对象注册到一个类中 * 通过该类实现全局访问操作对象 */ class Tree { private static $treeList = []; private fun ...
随机推荐
- Python:logging 的巧妙设计
引言 logging 的基本用法网上很多,这里就不介绍了.在引入正文之前,先来看一个需求: 假设需要将某功能封装成类库供他人使用,如何处理类库中的日志? 数年前在一个 C# 开发的项目中,我用了这样的 ...
- Git版本控制 —— IDE工具(IDEA)
本文介绍使用IDEA控制Git操作 关联本地Git客户端 首先要根据系统环境安装Git客户端 然后使用File --> Settings --> Version Control --&g ...
- DSAPI DS密法
DS密法是DYLIKE本人研发的一种针对文本字符串的高强度加密方法,本加密方法的优点是同源不同密,同一个源文本每次加密的结果都不同,长度也不同.密钥最大可达String类型的字符最大长度.缺点是解密时 ...
- Python动态绑定属性slots的使用
当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性.废话不多说,我们看一个例子: class Person(object): pass ...
- vue学习记录⑤(组件通信-父与子)
今天我们看一下组件通信. 经过前面几篇文章,我们已经可以构建出完整的单个组件,并利用路由使其串联起来访问了. 但这明显还是不够的.一个页面不可能就是个单组件,一般是由多个组件合成的.正因为如此,组件之 ...
- javascript语言精粹-笔记
walkDOM function walkTheDOM(node, func) { func(node); node = node.firstChild; while (node) { walkThe ...
- Android Jetpack之AppCompat(一)
今天我们来聊一聊有关AppCompat,作为Android Jetpack系列文章的开篇.说到Android Jetpack,我们先看一下这张图: 从图中我们可以看到,整个Android Jetpac ...
- SQL server 存储过程的建立和调用
存储过程的建立和调用 --1.1准备测试需要的数据库:test,数据表:物料表,采购表if not exists (select * from master.dbo.sysdatabases whe ...
- Windows 2008 打开声音重定向来听到远程主机音频
Windows 2008 Server在默认情况下,是禁止使用桌面桌面连接后播放声音的(提示音频服务未启用).可以通过下面的方法启用音频: 管理工具->远程桌面服务->远程桌面会话主机配置 ...
- pytest框架之命令行参数1
前言 pytest是一款强大的python自动化测试工具,可以胜任各种类型或者级别的软件测试工作.pytest提供了丰富的功能,包括assert重写,第三方插件,以及其他测试工具无法比拟的fixtur ...