设计模式第一讲(单例模式)

大家好,我是卡二条,很感谢大家关注我的个人微信公众号.为什么写这篇文章呢?主要是因为最近在公司负责架构这一块所遇到的一些问题,所感想而来。
到今天加入现在的团队也整整3个月了,一直负责架构这一块的工作内容,从最开始接手项目,可谓是十分糟糕,之前的项目经常出现数据不一致,扩展性差,异常不易排查等情况.在重构的过程中,将自己所学到的设计模式大量用到项目中,保证了项目后期的正常运行,同时也保证了项目的高可用、高扩展.于是便想着将自己了解到的设计模式通过文章的方式写出来,尽可能的保证每天分享一个设计模式,希望对大家有所帮助.如文章有什么不合适的地方,往大家指正.
分享的内容主要是以PHP代码作为演示代码,或许有时会参考其他的编程语言.分享的几点,主要是围绕以下几点.

  • 设计模式的定义
  • 设计模式的利与弊
  • 设计模式的代码演示
  • 设计模式的使用场景

其实个人最看中的是使用场景,很多的文章或者很多的书籍都只是单纯的讲理论知识,讲设计模式的好处等等,却缺乏对使用场景的分析,导致学习后不能很快的掌握.

单例模式的定义

作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。简而言之,就是去new 一个类的时候,不是每new 一次就创建一个对象,而是每次new 都是使用的同一个对象.可以查看下面的 var_dump()
函数打印的内容.

单例模式的三个要素

1.保存类唯一实例的静态变量.
2.构造函数和克隆函数必须是私有的,防止外部去实例化,这样就不存在单例模式的意义.

3.提供一个可供外部访问的 公共静态
方法,这个方法返回该类的唯一实例.

单例模式的优点

在PHP中的应用主要在于数据库应用, 所以一个应用中会存在大量的数据库操作, 在使用面向对象的方式开发时, 如果使用单例模式, 则可以避免大量的 new 操作消耗的资源。而不完全是对系统资源的节省, 可以避免重复实例化,因为 PHP 每次实例化一个类之后都会清理掉对应的资源,当再次使用的时候又会在重新去实例化一次。

单例模式演示

  • 不使用单例模式

    class Single {
    
        public function index() {
            return '';
        }
    }
    
    $single1 = new Single();
    $single2 = new Single();
    var_dump($single1);
    var_dump($single2);
    
    if ($single2 === $single1) {
        echo "是同一个对象";
    } else {
        echo "不是同一个对象";
    }
    

打印结果

object(Single)#1 (0) {
}
object(Single)#2 (0) {
}
不是同一个对象

  • 上面对象打印的#1,#2就是对象的序号.这就表明两个对象是不同的对象,同时对这两个对象做比较,===是全等于,要求数据类型,值相等.由于这两个变量只是类型相等(都是对象),但是值不想等,也就是说在内容中不属于同一片空间.因此便不属于同一个对象.
  • 使用单例模式

    class Single2 {
        // 1.声明一个静态属性,用户保存类的实例
        public static $instance;
        //3. 将构函数私有化,避免外部new(每new一次,就不是同一个实例)
        private function __construct() {
        }
        // 2.声明一个静态的公共方法,用户外部调用本类的实例
        public static function getInstance() {
            if (!(self::$instance instanceof self)) {
                self::$instance = new self;
            }
            return self::$instance;
        }
        //3. 克隆函数私有化,避免外部clone(每clone一次,就不是同一个实例)
        private function __clone() {
    
        }
    }
    $singleDemo1 = Single2::getInstance();
    $singleDemo2 = Single2::getInstance();
    
    var_dump($singleDemo1->getInstance());
    var_dump($singleDemo2->getInstance());
    if ($singleDemo1 === $singleDemo2) {
        echo "是同一个对象";
    } else {
        echo "不是同一个对象";
    }
    

打印结果

object(Single2)#3 (0) {
}
object(Single2)#3 (0) {
}
是同一个对象

  • 上面的两个#3都是属于不同的变量,但却是同一个对象.为什么是3,是上一个实例中,实例化了两次,因此这里就变成了3.

单例模式使用的场景

1.数据库连接,减少对数据库的 new 操作,从而减少内存资源和系统资源的消耗。
2.配置资源的共享,在一个系统中,配置资源都是全局的,使用单例模式也可以减少每次去读取配置带来的内存和系统资源的消耗。

在公司项目中用的是ThinkPHP框架,大量操作Redis,日志缓存的业务场景.这些都是我们自定义的类来操作,是因为ThinkPHP框架中操作Redis的可用函数过少,便考虑自行封装Redis操作类.同时,日志操作我们使用了Monolog( https://github.com/Seldaek/monolog)来处理日志,这些都属于自行封装的扩展.为了避免每次new
都会实例化一个对象,便在封装每一个扩展时,都使用到了单例模式.

总结

由于单例模式非常简单,今天通过代码分享,是为了分析单例模式其中的原理.由于文章会不断的更新,都会发布在个人的博客中,以后每一篇文章都可以点击 阅读原文按钮
进行查看最新内容.