zoukankan      html  css  js  c++  java
  • Yii2设计模式——单例模式

    应用举例

    在Yii.php中:

    require __DIR__ . '/BaseYii.php';
    
    // Yii框架的帮助类,提供框架基本的功能
    class Yii extends yiiBaseYii
    {
    }
    
    spl_autoload_register(['Yii', 'autoload'], true, true);
    Yii::$classMap = require __DIR__ . '/classes.php';
    // 只在入口脚本require '../Yii.php'时创建一个Container实例
    Yii::$container = new yiidiContainer();
    

    在BaseYii中相关的部分是,

    <?php
    
    class BaseYii
    {
        //Yii类维持一个DI Container的单例
        public static $container;
    
        //...
    
    	// 在Yii框架中,除了少数情况,都是通过Yii::createObject()来创建类的实例
    	// 而在Yii::createObject()中始终用到一个单例Yii::$container
        public static function createObject($type, array $params = [])
        {
            if (is_string($type)) {
                return static::$container->get($type, $params);
            } elseif (is_array($type) && isset($type['class'])) {
                $class = $type['class'];
                unset($type['class']);
                return static::$container->get($class, $params, $type);
            } elseif (is_callable($type, true)) {
                return static::$container->invoke($type, $params);
            } elseif (is_array($type)) {
                throw new InvalidConfigException('Object configuration must be an array containing a "class" element.');
            }
    
            throw new InvalidConfigException('Unsupported configuration type: ' . gettype($type));
        }
    
        //...
    }
    

    这里使用了单例模式。

    单例模式

    模式定义

    单例模式确保一个类只有一个实例,并提供一个全局访问点。当现实中只需要一个对象,或者为了节省系统资源,又或者是为了共享数据的时候可以使用单例模式

    代码实现

    我们先来看看单例模式的标准实现:

    final class Singleton
    {    
        /**
         * @var Singleton
         * 维持一个对自身的引用,并保证其唯一性
         */
        private static $instance;
    
        
        // 获取实例唯一的入口
        public static function getInstance(): Singleton
        {
            if (null === static::$instance) {
                static::$instance = new static();
            }
    
            return static::$instance;
        }
        
        // 不允许通过new的方式产生,只能通过Singleton::getInstance()方法
        private function __construct()
        {
        }
        
        // 也不允许clone()方法,此方法也会产生一个新的实例
        private function __clone()
        {
        }
        
        // 也不允许反序列化,因为反序列化也会产生一个新的实例
        private function __wakeup()
        {
        }
    }
    

    单例模式不允许产生单例的类被继承,不允许通过new方式产生,除了规定的getInstance()方法,别的实例化的途径基本被堵死。而在类的内部维持一个对自身的引用,并保证其是唯一的。

    单例模式估计是所有涉及模式中最简单的了,在PHP和Yii中很少见到直接这么使用的,更多的是其变化的形式。

    Yii的单例模式

    Yii使用单例的场景非常多,比如请求开始创建的Application,Yii,Request,Response等对象功能都十分丰富且开销也很大,维持一个单例就可供请求的整个生命周期使用。在请求开始即创建,请求结束自行销毁,中间不销毁也不创建。这些对象使用了单例没有疑问,但是这些单例的产生、管理和使用却是有不同讲究的。

    对象如何创建又如何维护,恐怕任何一个PHP框架都绕不开这个问题。Yii2采用服务定位器和依赖注入容器来提供大部分对象。在容器中使用单例好处是非常明显的。至少可以表现在节省内存和公用组件方面。

    节省内存

    Yii::$container 在内存中仅有一份,所有使用DI容器的场合(Application/Module等)都用到这个DI容器。 这就节省了大量的内存空间和反复构造实例的时间。

    共用组件

    更为重要的是,DI容器的单例化,使得Yii不同的模块共用组件成为可能。 可以想像,由于共用了DI容器,容器里面的内容也是共享的。因此,你可以在A模块中改变某个组件的状态,而B模块中可以了解到这一状态变化。 但是,如果不采用单例模式,而是每个模块(Application/Module)都维护一个自己的DI容器, 要实现这一点难度会大得多。所以,这种共享DI容器的设计是必然的、合理的。

  • 相关阅读:
    系统架构师学习笔记_第十一章(下)
    通过IronRuby和C#学习RUBY系列[0]
    TIPS to comment your code
    超级简单:DIV布局
    js 查询XML数据添加到HTML select控件
    《架构之美》读书笔记(一)
    18个不常见的C#关键字,您使用过几个?
    如何成为人尽皆知的C#开发人员
    实现Visual Studio 2010一个很简单的很酷的扩展
    一种简单的直观的高效的权限设计
  • 原文地址:https://www.cnblogs.com/minirice/p/10141898.html
Copyright © 2011-2022 走看看