单例【Singleton】

实例

饿汉式

注:java中饿单例模式性能 > 懒单例模式,c++中一般使用懒单例模式

优点

加载即创建,线程安全

缺点

资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化

// 饿汉式(java推荐, PHP不支持)
class Singleton
{
    /**
     * @var Singleton
     */
    private static Singleton $instance = new self; // PHP不支持这样写

    private function __construct()
    {
        // Do nothing
    }

    private function __clone()
    {
        // Do nothing
    }

    private function __wakeup()
    {
        // Do nothing
    }

    /**
     * @return Singleton
     */
    public static function getInstance(): Singleton
    {
        if $instance {
            self::$instance = new self;
        }
        return self::$instance;
    }
}

var_dumpgetInstance();
/*
class Singleton#1 (0) {
}
*/

懒汉式

优点

避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。

缺点

懒汉式默认不安全;加锁可保证安全,但会牺牲多线程性能

4私1公

  1. 私有构造方法, 防止从类外部实例化
  2. 私有静态属性, 初始值null, 保存实例
  3. 私有克隆方法, 防止克隆
  4. 私有重建方法, 防止重建对象
  5. 公共的静态方法, 访问这个实例
class Singleton
{
    /**
     * 私有属性,用于保存当前类实例化后的对象
     * @var Singleton|null
     */
    private static ?Singleton $instance = null;

    // 私有方法,禁止外部程序使用new实例化,只能在内部new
    private function __construct()
    {
    }

    // 私有方法,禁止克隆对象
    private function __clone()
    {
    }

    // 私有方法,禁止重建对象
    private function __wakeup()
    {
    }

    /**
     * 公共方法,这是获取当前类对象的唯一方式
     * @return Singleton|null
     */
    public static function getInstance(): ?Singleton
    {
        // 多个线程判断instance都为null时,
        // 在执行new操作时多线程会出现重复情况
        if $instance {
            self::$instance = new self;
        }

        return self::$instance;
    }
}

var_dumpgetInstance();

总结

单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式因为Singleton类封装它的唯一实例,这样它可以严格地控制客户怎样访问以及何时访问它。简单地说就是对唯一实例的受控访问。

意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

优点

缺点

使用场景

适用于需要频繁使用、创建耗时/耗资源,且对象必须是唯一共享的场合。

注意事项

1. 线程安全问题 (并发创建)

2. 反射攻击

3. 继承限制