共计 3252 个字符,预计需要花费 9 分钟才能阅读完成。
单例模式相对是在罕用以及面试常问设计模式中排名首位的。一方面它够简略,喋喋不休就能说明确。另一方面,它又够简单,它的实现不仅仅只有一种模式,而且在 Java 等异步语言中还要思考多线程加锁的问题。所以在面试时,千万不要认为面试官出单例模式的问题就放松了,这个模式真的是可深可浅,也极其能体现一个开发者的程度。因为只有工作过一段时间,不可避免的就会接触到这个模式。
Gof 类图及解释
GoF 定义:保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。
GoF 类图
代码实现
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()办法取得全局惟一的一个对象。
$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 零碎服务器中的那惟一一份实在的花名册
残缺代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/21.singleton/source/singleton.php
实例
既然下面说过数据库操作类和网络申请类都很喜爱用单例模式,那么咱们就来实现一个 Http 申请类的单例模式的开发。记得在很早前做 Android 的时候,还没有当初这么多的框架,Http 申请都是本人封装的,网上的教程中大部分也都是采取的单例模式。
缓存类图
残缺源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/21.singleton/source/singleton-http.php
<?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 static $instance = new HttpService();。这样能够省略掉 GetInstance()办法,然而这个动态变量不论用不必都会间接实例化进去占用内存。这种单例就叫做饿汉式单例模式。
- 咱们的代码和例子很显著不是饿汉式的,这种模式叫做懒汉式。你要被动的来用 GetInstance()获取,我才会创建对象。
- 懒汉式在多线程的利用中,如 java 多线程或者 PHP 中应用 swoole 之后,会呈现反复创立的问题,而且这屡次创立的都不是同一个对象了。这时个别会应用双重检测来来确保全局还是只有惟一的一个对象。具体代码大家能够去本人找一下。饿汉式不会有问题,饿汉式自身就曾经给动态属性赋值了,不会再扭转。具体能够参考动态类相干文章(公众号内查问《PHP 中的 static》或掘金 https://juejin.im/post/5cb5b2926fb9a068664c1ac5)。
- 还有一种形式是动态外部类的创立形式。这种平时就不多见了,它的资源利用率高。将动态变量放在办法内,使动态变量成为办法内的变量而不是类中的变量。它能够让单例对象调用本身的静态方法和属性。
下期看点
是不是忽然发现单例真的没有设想中的那么简略啊,还有这么多我不晓得的货色。一个人从晓得本人晓得到晓得本人不晓得就是回升了一个台阶,再上来就是不晓得本人晓得了,到了这个阶段的码农那可都是高手中的高手了。单例模式就是这样一个经典罕用的超级模式。为什么叫超级模式呢?因为它和工厂两大模式真的能够说是面试必备题,不学可不行哦!下一个退场的是 状态模式,从名字就能够看出,和类的状态无关,但具体是干嘛的呢?咱们下回见。
各自媒体平台均可搜寻【硬核项目经理】