资讯专栏INFORMATION COLUMN

浅入理解单例模式

CoyPan / 2413人阅读

摘要:实现我们在这里引入了一个私有的构造函数,这样,外部就无法实例化这个对象了。对于这个类,我们无法生成第二个对象,因为它的构造函数是私有的,并且方法是私有的,而且,在判断已经有了一个实例的情况下默认返回该实例。这就是单例模式。

问题 恼人的全局变量

在 PHP 中,甚至不只 PHP 中,我们都会用到全局变量,以保存全局状态。可是,往往全局变量是全局共享的,任何地方任何代码都有可能将其覆盖。例如,我们定义一个全局变量叫做 PHONE。我们在某一行代码中,将其定义成了 iPhone,但是我们不小心在另一行代码中将其覆写成了 Nokia。这就非常的尴尬了,因为本来我们并不想它被覆写。

繁琐的参数传递

在一个系统中,我们会定义许多的方法,生成很多的对象。有时候,我们会使用很多的方法,对同一个对象做操作。在不使用全局变量的情况下,我们需要将对象作为参数传入方法中。但是这样传递同一个对象,可能会造成混乱,还可能造成不必要的依赖。

其实我们只需要一个全局可访问的对象就可以解决这个,但是全局变量又会出现我们上面的说的问题。

解决 目标

我们要解决这些问题,我们对这样的对象有下面的几个目标。

这个对象,无论在哪里都能访问,就想全局变量一样。

这个对象,和全局变量不同,不能被覆写。

这个对象,整个系统中只存在一个,对它的修改在整个系统中都能被感知到。

以上的几个目标,就是我们所需要的,也就是单例模式的特征。

UML

实现
class Preference
{
    private static $instance;
    private $props = [];
    
    private __construct() {}
    
    public static function getInstance()
    {
        if (empty(self::$instance)) {
            self::$instance = new Preference();
        }
        
        return self::$instance;
    }
    
    public function setProperty($key, $value)
    {
        $this->props[$key] = $value;
    }
    
    public function getProperty($key)
    {
        return $this->props[$key];
    }

    private function __clone() {}
    
    private function __sleep() {}
    
    private function __wakeup() {}
}

我们在这里引入了一个私有的构造函数,这样,外部就无法实例化这个对象了。同时,我们使用 getInstance 方法来获取具体的实例,而无法去覆写它,这就达成了第二个目标。

由于 $instancegetInstance 都是静态的,所以我们可以通过 Preference::getInstance() 访问,具体的实例。这样就使得全局都可以访问到它了,它就像全局变量一样了,这就达成了第一个目标了。

对于这个类,我们无法生成第二个对象,因为它的构造函数是私有的,并且 __clone 方法是私有的,而且,getInstance 在判断已经有了一个实例的情况下默认返回该实例。这就达成了第三个目标了。

同时,我们也尽量避免序列化这个实例,所以我们给 __wakeup__sleep 这两个魔术方法私有。

这就是单例模式。

后记

对于单例模式,其实没有那么高大上。只不过是更改的对象的访问范围,以及对象始终存在,仅此而已。

最后,本文章是作者在学习设计模式时的感想。部分参考自《深入 PHP 面向对象、模式与实践(第 3 版)》。如有错误,感谢大神不吝赐教。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30679.html

相关文章

  • javascript知识点

    摘要:模块化是随着前端技术的发展,前端代码爆炸式增长后,工程化所采取的必然措施。目前模块化的思想分为和。特别指出,事件不等同于异步,回调也不等同于异步。将会讨论安全的类型检测惰性载入函数冻结对象定时器等话题。 Vue.js 前后端同构方案之准备篇——代码优化 目前 Vue.js 的火爆不亚于当初的 React,本人对写代码有洁癖,代码也是艺术。此篇是准备篇,工欲善其事,必先利其器。我们先在代...

    Karrdy 评论0 收藏0
  • vuex浅入浅出

    摘要:来自不同视图的行为需要变更同一状态。图解后端的行为,响应在上的用户输入导致的状态变化。中的非常类似于事件每个都有一个字符串的事件类型和一个回调函数。 什么是Vuex? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 Vuex采用和Redux类似的单向数据流的方式来管理数据。用户...

    琛h。 评论0 收藏0
  • Java 总结

    摘要:中的详解必修个多线程问题总结个多线程问题总结有哪些源代码看了后让你收获很多,代码思维和能力有较大的提升有哪些源代码看了后让你收获很多,代码思维和能力有较大的提升开源的运行原理从虚拟机工作流程看运行原理。 自己实现集合框架 (三): 单链表的实现 自己实现集合框架 (三): 单链表的实现 基于 POI 封装 ExcelUtil 精简的 Excel 导入导出 由于 poi 本身只是针对于 ...

    caspar 评论0 收藏0
  • java 基础 - 收藏集 - 掘金

    摘要:基础知识复习后端掘金的作用表示静态修饰符,使用修饰的变量,在中分配内存后一直存在,直到程序退出才释放空间。将对象编码为字节流称之为序列化,反之将字节流重建成对象称之为反序列化。 Java 学习过程|完整思维导图 - 后端 - 掘金JVM 1. 内存模型( 内存分为几部分? 堆溢出、栈溢出原因及实例?线上如何排查?) 2. 类加载机制 3. 垃圾回收 Java基础 什么是接口?什么是抽象...

    makeFoxPlay 评论0 收藏0
  • java 基础 - 收藏集 - 掘金

    摘要:基础知识复习后端掘金的作用表示静态修饰符,使用修饰的变量,在中分配内存后一直存在,直到程序退出才释放空间。将对象编码为字节流称之为序列化,反之将字节流重建成对象称之为反序列化。 Java 学习过程|完整思维导图 - 后端 - 掘金JVM 1. 内存模型( 内存分为几部分? 堆溢出、栈溢出原因及实例?线上如何排查?) 2. 类加载机制 3. 垃圾回收 Java基础 什么是接口?什么是抽象...

    Markxu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<