美文网首页
PHP设计模式(1):单例模式(Singleton)

PHP设计模式(1):单例模式(Singleton)

作者: MonkeyNote | 来源:发表于2018-10-18 15:54 被阅读0次
什么是单例模式

顾名思义,就是只有一个实例。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

为什么使用单例模式
  1. PHP的应用主要在于数据库应用,一个应用中会存在大量的数据库操作,在使用面向对象的方式开发时,如果使用单例模式,
    则可以避免大量的 new 操作消耗的资源,还可以减少数据库连接这样就不容易出现 too many connections 情况。
  2. 如果系统中需要有一个类来全局控制某些配置信息,那么使用单例模式可以很方便的实现。
  3. 在一次页面请求中,便于进行调试,因为所有的代码(例如数据库操作类db)都集中在一个类中,我们可以在类中设置钩子,输出日志,从而避免到处 var_dump,echo。
单例模式结构图
PHP设计模式(1):单例模式(Singleton)
单例模式的实现
  1. 私有化一个属性用于存放唯一的一个实例
  2. 私有化构造方法,私有化克隆方法,用来创建并只允许创建一个实例
  3. 公有化静态方法,用于向系统提供这个实例
代码实现
class Singleton
{
    // 存放实例
    private static $_instance = null;

    // 私有化构造方法
    private function __construct() 
    {
        echo '单例模式的实例被构造了';
    }
    
    // 私有化克隆方法
    private function __clone() {}

    // 公有化获取实例方法
    public static function getInstance() 
    {
        if (!(self::$_instance instanceof Singleton)) {
            self::$_instance = new Singleton();
        }
        return self::$_instance;
    }
}

$singleton = Singleton::getInstance();
优点:
  1. 因为静态方法可以在全局范围内被访问,当我们需要一个单例模式的对象时,只需调用getInstance方法,获取先前实例化的对象,无需重新实例化。
  2. 由于单例模式在内存中只有一个实例,减少内存开支,特别是一个对象需要频繁地创建销毁时,而且创建或销毁时性能又无法优化,单例模式就非常明显了
  3. 由于单例模式只生成一个实例,所以,减少系统的性能开销,当一个对象产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
  4. 单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作
  5. 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。
缺点:
  1. 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
  2. 单例对象如果持有Context,那么很容易引发内存泄漏,此时需要注意传递给单例对象的Context最好是Application Context。
使用 Trait 关键字实现类似于继承单例类的功能
Trait Singleton
{
    //存放实例
    private static $_instance = null;
    
    //私有化克隆方法
    private function __clone() {}

    //公有化获取实例方法
    public static function getInstance() 
    {
        $class = __CLASS__;
        if (!(self::$_instance instanceof $class)) {
            self::$_instance = new $class();
        }
        return self::$_instance;
    }
}

class DB
{
    private function __construct() 
    {
        echo __CLASS__ . PHP_EOL;
    }
}

class DBHandle extends DB
{
    use Singleton;
    private function __construct() 
    {
        echo '单例模式的实例被构造了';
    }
}

$handle = DBHandle::getInstance();

// 注意若父类方法为public,则子类只能为pubic,若父类为private,子类为public,protected,private都可以。
单例模式特点(三私一公)
  1. 私有的构造方法(防止类外实例化)
  2. 私有的克隆方法(防止通过克隆生成对象)
  3. 私有的静态属性(保存类的实例)
  4. 公有的静态方法(调取这个类相当一个接口)

补充,大多数书籍介绍单例模式,都会讲三私一公,公有化静态方法作为提供对象的接口,私有属性用于存放唯一一个单例对象。私有化构造方法,私有化克隆方法保证只存在一个单例。
但实际上,虽然我们无法通过 new 关键字和 clone 出一个新的对象,但我们若想得到一个新对象。还是有办法的,那就是通过序列化和反序列化得到一个对象。私有化 sleep() 和 wakeup() 方法依然无法阻止通过这种方法得到一个新对象。或许真得要阻止,你只能去 __wakeup 添加删除一个实例的代码,保证反序列化增加一个对象,你就删除一个。不过这样貌似有点怪异。

相关文章

网友评论

      本文标题:PHP设计模式(1):单例模式(Singleton)

      本文链接:https://www.haomeiwen.com/subject/iwujzftx.html