美文网首页
2.单例模式 Singleton

2.单例模式 Singleton

作者: 带带吴腾跃 | 来源:发表于2019-11-17 16:08 被阅读0次

单例模式是众多设计模式中较为常见的一种。定义单例模式一般满足以下两个定义:

  • 1.保证一个类只创建一个实例。
  • 2.提供对该实例的全局访问点。

GoF《设计模式》实现单例设计模式的代码:Lazy Singleton

class Singleton
{
public:
    static Singleton& Instance()
    {
        if (instance_ == NULL)
        {
            instance_ = new Singleton;
        }
        return *instance_;
    }
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
private:
    static Singleton* instance_;
};
  • 上述实现中把构造函数声明为私有方法,根本上杜绝外部使用构造函数生成新的类实例。
  • 同时禁用拷贝函数与赋值操作符(声明为私有但是不提供实现)避免通过拷贝函数或赋值操作生成新实例。
  • 提供静态方法Instance()作为全局访问点,先判断有无现成实例,有直接返回,无就新建一个实例并把实例的指针存储在私有的静态属性instance_中。
  • Instance()的返回值类型是引用而不是指针,因为指针可能会被外部调用delete掉。

但上述实现有一个问题,就是如果现在有两个线程A和B,同时通过instance_ == NULL的判断,那么A和B都会创建新实例。所以单例设计模式保证生成唯一实例的规则被打破了。

  • 所以上述实现只适用于单线程环境!

下面来看另一种实现: Eager Singleton

{
public:
    static Singleton& Instance()
    {
        return instance;
    }
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
private:
    static Singleton instance; // 
};
  • 上述实现中程序开始时(静态属性instance初始化)的时候就已经创建了实例。
  • 在main函数之前初始化,没有线程安全的问题。但潜在问题如果函数外的static对象(nolocal static)在不同编译单元(就是cpp文件和其包含的头文件)中的初始化顺序是为定义的。如果在初始化完成之前就调用Instance()方法则会返回一个未定义的实例。
    注:全局静态变量同一个文件中先定义先初始化,不同的文件中不确定,也就是不同cpp文件里的全局static变量初始化顺序是不可控的。

所以上述实现还是有弊端!

再来看一种更优雅的单例模式实现:Meyers Singleton

class Singleton
{
public:
    static Singleton& Instance()
    {
        static Singleton instance;
        return instance;
    }
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
};
  • 上述实现使用local static 局部静态变量,当第一次访问Instance()方法时才创建实例。完美的解决了Eager Singleton中的问题!

相关文章

网友评论

      本文标题:2.单例模式 Singleton

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