绝对是常用和常问的面试设计模式之首。一方面,它足够简单,几句话就能解释清楚。另一方面,它足够复杂。它的实现不仅是一种形式,还考虑了Java等异步语言中多线程加锁的问题。所以在面试的时候,不要以为面试官问出单例模式的问题就会放松。这种模式真是有深有浅,也能体现一个开发者的水平。因为只要你工作一段时间,就不可避免地会接触到这个模型。Gof类图及解释GoF定义:保证一个类只有一个实例,并提供一个全局访问点来访问它。GoF类图代码实现类Singleton{privatestatic$uniqueInstance;private$singletonData='单例类内部数据';privatefunction__construct(){//构造方法是私有的,外部不能直接实例化该类}publicstaticfunctionGetInstance(){if(self::$uniqueInstance==null){self::$uniqueInstance=新单例();}returnself::$uniqueInstance;}publicfunctionSingletonOperation(){$this->singletonData='修改实例类的singleton内部数据';}publicfunctionGetSigletonData(){return$this->singletonData;}}是的,核心就是这么一个单例类,没有别的。让静态变量实例化后自己保存。当需要这个对象时,调用GetInstance()方法获取一个全局唯一的对象。$singletonA=Singleton::GetInstance();echo$singletonA->GetSigletonData(),PHP_EOL;$singletonB=Singleton::GetInstance();if($singletonA===$singletonB){echo'同一个对象',PHP_EOL;}$singletonA->SingletonOperation();//这里修改的是Aecho$singletonB->GetSigletonData(),PHP_EOL;客户端调用,我们会发现$singletonA和$singletonB是完全相同的对象。没错,从代码中可以看出,单例最大的用处就是让我们的对象全局唯一。那么全球独一无二的好处是什么?有些类的创建成本很高,我们不需要每次都使用一个新对象。它们可以与一个对象重复使用。他们没有需要改变的属性或状态,只是提供一些公共服务。比如数据库操作类,网络请求类,日志操作类,配置管理服务等。曾经有面试官问过PHP中单例是不是就只有一个?如果是在一个进程下,也就是在一个fpm下,当然是唯一的。肯定不是nginx同步拉起的多个fpm中唯一的一个。每个进程一个!单例模式的优点:控制对唯一实例的访问;狭窄的命名空间;允许改进操作和表示;允许可变数量的实例;比类操作更灵活。Laravel在IoC容器部分使用单例模式。我们会在以后的Laravel系列文章中讲解容器部分的内容。我们可以在Illuminate\Container\Container类中找到单例方法。它在绑定方法中调用getClosure方法。如果继续跟踪,你会发现他们最终会调用Container的make或者build方法来实例化类。无论是make还是build方法,它们都会有一个单例判断,即判断类是否已经被实例化或者是否已经存在于容器中。.如果(!$reflector->isInstantiable())在构建中。公司越来越大,但是我们只有一个所有公司的花名册(单例类),存储在我们的OA系统中。我怕的是每个部门都有自己的花名册,会造成混乱。比如更新不及时,会漏掉其他部门的新员工或离职员工。其他部门需要的时候,可以查看所有的花名册,也可以根据整个花名册创建和修改自己的部门。但是在OA系统中,其实他们修改的是总花名册里面的内容。大家维护的其实是OA系统服务器中保存的唯一真实的花名册。完整代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/21.singleton/source/singleton.phpinstance由于上面提到了数据库操作类和网络请求类喜欢使用单例模式,那么我们就实现一个Http请求类单例模式的开发。记得很久以前做安卓的时候,现在没有那么多框架。http请求都是自己封装的,网上的教程也大多采用单例模式。缓存类图完整源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/21.singleton/source/singleton-http.phpPost();$httpA->Get();$httpB=newHttpService();$httpB->Post();$httpB->Get();var_dump($httpA==$httpB);是不是解释起来还是很简单的,这里就不说这种形式的单例了,说说其他几种这种形式的单例在Java等静态语言中,静态变量可以直接new对象,直接赋值在声明$instance的时候给他赋值,比如privatestatic$instance=newHttpService();。这样就可以省略GetInstance()方法,但是这个静态变量不管用不用都会直接实例化占用内存。这种单例被称为饥饿的中国单例模式。我们的代码和例子显然不是饿了,这种形式叫做懒惰风格。你要主动用GetInstance()去获取,我来创建对象。多线程应用中的lazy风格,比如java多线程或者PHP中使用swoole后,会出现重复创建的问题,多次创建的对象不是同一个对象。这时候一般会采用双重检测来保证全局只有一个对象。具体代码可以自己找。HungryStyle不会有问题,因为HungryStyle本身已经给静态属性赋值了,不会改变。具体可以参考静态类的相关文章(在公众号《PHP中的static》或掘金https://juejin.im/post/5cb5b2926fb9a068664c1ac5内查询)。另一种方法是创建静态内部类。这通常很少见,并且其资源利用率很高。将静态变量放在方法内部,使静态变量成为方法内部的变量,而不是类中的变量。它允许单例对象调用它们自己的静态方法和属性。下一期看什么?是不是突然发现,单例真的没有想象中的那么简单,不知道的东西太多了。一个人从知道自己知道,到知道自己不知道,上升了一个层次。如果他倒下了,他不知道他知道。到了这个阶段的coder,都是高手中的高手。单例模式就是这样一个经典且常用的超级模式。为什么叫超级模式呢?因为它和工厂的两大机型真的可以说是面试必考题,学不会!下一个出现的是状态模式。从名字就可以看出,它与类的状态有关,但它是干什么用的呢?下次见。各媒体平台均可搜索【硬核项目经理】
