PHP设计模式之单例模式

PHP设计模式之单例模式

单例模式绝对是在经常使用以及面试常问设计模式中排名首位的。一方面它够简单,三言两语就能说明白。另外一方面,它又够复杂,它的实现不只仅只有一种形式,并且在Java等异步语言中还要考虑多线程加锁的问题。因此在面试时,千万不要觉得面试官出单例模式的问题就放松了,这个模式真的是可深可浅,也极其能体现一个开发者的水平。由于只要工做过一段时间,不可避免的就会接触到这个模式。php

Gof类图及解释

GoF定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。java

GoF类图nginx

单例模式

代码实现git

class Singleton {
    private static $uniqueInstance;
    private $singletonData = '单例类内部数据';

    private function __construct() {
        // 构造方法私有化,外部不能直接实例化这个类
    }

    public static function GetInstance() {
        if (self::$uniqueInstance == null) {
            self::$uniqueInstance = new Singleton();
        }
        return self::$uniqueInstance;
    }

    public function SingletonOperation(){
        $this->singletonData = '修改单例类内部数据';
    }

    public function GetSigletonData() {
        return $this->singletonData;
    }

}
复制代码

没错,核心就是这样一个单例类,没别的了。让静态变量保存实例化后的本身。当须要这个对象的时候,调用GetInstance()方法得到全局惟一的一个对象。github

$singletonA = Singleton::GetInstance();
echo $singletonA->GetSigletonData(), PHP_EOL;

$singletonB = Singleton::GetInstance();

if ($singletonA === $singletonB) {
    echo '相同的对象', PHP_EOL;
}
$singletonA->SingletonOperation(); // 这里修改的是A
echo $singletonB->GetSigletonData(), PHP_EOL;
复制代码

客户端的调用,咱们会发现singletonA和singletonB是彻底同样的对象。面试

  • 没错,从代码中就能够看出,单例最大的用途就是让咱们的对象全局惟一。
  • 那么全局惟一有什么好处呢?有些类的建立开销很大,并且并不须要咱们每次都使用新的对象,彻底能够一个对象进行复用,它们并无须要变化的属性或状态,只是提供一些公共服务。好比数据库操做类、网络请求类、日志操做类、配置管理服务等等
  • 曾经有过面试官问过,单例在PHP中究竟是不是惟一的?若是在一个进程下,也就是一个fpm下,固然是惟一的。nginx同步拉起的多个fpm中那确定就不是惟一的啦。一个进程一个嘛!
  • 单例模式的优势:对惟一实例的受控访问;缩小命名空间;容许对操做和表示的精化;容许可变数目的实例;比类操做更灵活。
  • Laravel中在IoC容器部分使用了单例模式。关于容器部分的内容咱们会在未来的Laravel系列文章中讲解。咱们能够在Illuminate\Container\Container类中找到singleton方法。它调用了bind方法中的getClosure方法。继续追踪会发现他们最终会调用Container的make或build方法来进行实例化类,不论是make仍是build方法,他们都会有单例的判断,也就是判断类是否被实例化过或者在容器中已存在。build中的if (!$reflector->isInstantiable())。

公司愈来愈大,但咱们的所有公司的花名册都只有一份(单例类),保存在咱们的OA系统中。怕的就是各个部门拥有各本身的花名册后会产生混乱,好比更新不及时漏掉了其余部门新入职或者离职的员工。其余部门在须要的时候,能够去查看所有的花名册,也能够在所有花名册的基础上创建修改本身部门的部分。可是在OA系统中,其实他们修改的仍是那一份总的花名册中的内容,你们维护的其实都是保存在OA系统服务器中的那惟一一份真实的花名册数据库

完整代码:github.com/zhangyue050…设计模式

实例

既然上面说过数据库操做类和网络请求类都很喜欢用单例模式,那么咱们就来实现一个Http请求类的单例模式的开发。记得在很早前作Android的时候,尚未如今这么多的框架,Http请求都是本身封装的,网上的教程中大部分也都是采起的单例模式。缓存

缓存类图服务器

缓存模板方法模式版

完整源码:github.com/zhangyue050…

<?php 

class HttpService{
    private static $instance;

    public function GetInstance(){
        if(self::$instance == NULL){
            self::$instance = new HttpService();
        }
        return self::$instance;
    }

    public function Post(){
        echo '发送Post请求', PHP_EOL;
    }

    public function Get(){
        echo '发送Get请求', PHP_EOL;
    }
}

$httpA = new HttpService();
$httpA->Post();
$httpA->Get();

$httpB = new HttpService();
$httpB->Post();
$httpB->Get();

var_dump($httpA == $httpB);

复制代码

说明

  • 是否是依然很简单,这里就很少说这种形式的单例了,咱们说说另外几种形式的单例
  • 在Java等静态语言中,静态变量能够直接new对象,在声明instance的时候直接给他赋值,好比 private staticinstance = new HttpService();。这样能够省略掉GetInstance()方法,可是这个静态变量无论用不用都会直接实例化出来占用内存。这种单例就叫作饿汉式单例模式。
  • 咱们的代码和例子很明显不是饿汉式的,这种形式叫作懒汉式。你要主动的来用GetInstance()获取,我才会建立对象。
  • 懒汉式在多线程的应用中,如java多线程或者PHP中使用swoole以后,会出现重复建立的问题,并且这屡次建立的都不是同一个对象了。这时通常会使用双重检测来来确保全局仍是只有惟一的一个对象。具体代码你们能够去本身找一下。饿汉式不会有问题,饿汉式自己就已经给静态属性赋值了,不会再改变。具体能够参考静态类相关文章(公众号内查询《PHP中的static》或掘金juejin.im/post/5cb5b2…)。
  • 还有一种方式是静态内部类的建立方式。这种日常就很少见了,它的资源利用率高。将静态变量放在方法内,使静态变量成为方法内的变量而不是类中的变量。它可让单例对象调用自身的静态方法和属性。

下期看点

是否是忽然发现单例真的没有想象中的那么简单啊,还有这么多我不知道的东西。一我的从知道本身知道到知道本身不知道就是上升了一个台阶,再下去就是不知道本身知道了,到了这个阶段的码农那可都是高手中的高手了。单例模式就是这样一个经典经常使用的超级模式。为何叫超级模式呢?由于它和工厂两大模式真的能够说是面试必备题,不学可不行哦!下一个登场的是状态模式,从名字就能够看出,和类的状态有关,但具体是干吗的呢?咱们下回见。

相关文章
相关标签/搜索