设计模式实践--单例模式

介绍

数学与逻辑学中,singleton定义为“有且仅有一个元素的集合”。
单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。

一个典型的单例模式在php中的实现如下:

class test 
{
    private static $_instance;    //保存类实例的私有静态成员变量

    //定义一个私有的构造函数,确保单例类不能通过new关键字实例化,只能被其自身实例化
    private final function __construct() 
    {
        echo 'test __construct';
    }

    //定义私有的__clone()方法,确保单例类不能被复制或克隆
    private function __clone() {}

    //对外提供获取唯一实例的方法
    public static function getInstance() 
    {
        //检测类是否被实例化
        if ( ! (self::$_instance instanceof self) ) {
            self::$_instance = new test();
        }
        return self::$_instance;
    }
}

test::getInstance();

类自身只提供一个对外的getInstance()方法来获取实例,这里的关键在于用了一个静态变量$_instance来保存实例,静态变量是属于类的,在php的一次生命周期中,它会一直存在,只要有人需要拿到这个类的对象,getInstance() 就会去把唯一的$_instance返回回来,实现了对象的唯一性。

在容器中实现单例

ioc容器简介

Sakura框架是基于一个叫做container的东西的,这个container是一个类,它有一个叫做$bindings的数组,这个数组中存放的是被bind上去一对键值,key是一个字符串,用来标示,value可能是类的名字,或者一个匿名函数,总之它会告诉container当有人想从容器中根据key来取出一个对象的时候,该如何去制造出这个对象。这个概念是和laravel一致的。

容器中的单例

容器中的单例模式和上述的典型单例模式最大的区别就是,典型的单例模式中类自身会保证自己只被实例化一次。但是由于在container中,所有对象都是通过container来实例化的,所以自然,保证对象的唯一性这个职责也要交给container。
在容器中,普通对象的绑定通过bind()方法,示例如下:

$app = new System\Foundation\Container();

$app->bind('test', \System\test::class);

而要绑定一个单例对象的时候则用下面的方式:

$app->singleton('test', \System\test::class);

在容器的实现中,singleton()方法的代码:

public function singleton($abstract, $concrete = null)
{
    $this->bind($abstract, $concrete, true);
}

public function bind($abstract, $concrete = null, $shared = false)
{
    if ( ! $concrete instanceof Closure ) {
        $concrete = $this->getClosure($abstract, $concrete);
    }
    $this->bindings[$abstract] = compact('concrete', 'shared');
}

可以看到,唯一的区别就是把$this->bindings[$abstract]的shared设置为了true。在使用make方法来取出对象的时候,容器会根据当前$abstract对应的shared属性来判断是否需要单例它。
在container的make()方法中,用了如下代码:

if ($this->isShared($abstract)) {
    $this->instances[$abstract] = $object;
}

isShared()方法来判断是否为单例,如果是,则把该对象写入到容器的$this->instances[]中,这样当下次调用容器的make()方法来再次取出该对象的时候,先用如下代码进行判断,$this->instances[]中是否已经保存有了这个对象,如果有,直接返回该对象,这样就保证了对象的唯一性。

if (isset($this->instances[$abstract])) {
    return $this->instances[$abstract];
}

完整的代码请看

https://github.com/zhaohehe/Sakura/blob/ma...

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!