【设计模式总结】单例模式 - 木东驿站 - Powered by MoodBlog

CONTENT

【设计模式总结】单例模式

单例模式定义

确保某一个类只有一个实例,而且自行实例化并向整个系统提供整个实例。

简单点说,就是这个类在运行过程中只能初始化一次,只能产生一个对象。

单例模式.png

实现要点

一、为了确保这个类只有一个实例,我们应该禁止用户创建实例化对象,即把构造方法设置为private。

二、实现自行实例化有两种方式:懒汉式和饿汉式,懒汉式就是等用户需要的时候系统创建对象,饿汉式是在类加载完成后就创建实例化对象。


懒汉式代码


注意:为了防止对象被拷贝,我们要把拷贝构造函数和拷贝赋值运算符函数删除,上面是c++11中的写法。在旧版本c++中,应该把这两个函数设为private。

class Singleton
{
public:
    static Singleton* getInstance();
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
private:
    static Singleton* singleton;
    Singleton(){};
};
Singleton* Singleton::singleton = NULL;
Singleton* Singleton::getInstance()
{
    if(singleton == NULL)
        {
            singleton = new Singleton();
        }
    return singleton;
}

多线程安全

上面懒汉式代码在单线程程序中没有问题,但是如果出现在多线程环境下,会出现单例模式的线程同步问题。比如一个线程执行到single = new Singleton(),但是还没有初始化完,没有返回结果。这时候另一个线程判断if(singleton == null)通过,便开始创建第二个对象,这样系统中就存在两个对象。

怎么解决呢?肯定是加锁了。但是加锁会导致性能降低,一般情况下不需要在乎这点消耗,毕竟只创建一次。但是程序员们总是喜欢精益求精,所以创造了更好的解决方法。在java中可以使用双重检测法在避免竞争问题的同时保证性能。但在c++中这种方法未必可靠,因为编译器会对代码进行优化,可能出现乱序执行问题,volitile并不能保证正确性。

在linux中系统提供了一个pthread_once的函数,它保证函数不会执行多次,我们可以使用它来执行初始化方法。(《linux多线程服务端编程》)

如果不是在linux环境下呢?我在网上看到这样一种写法,利用静态变量实现线程安全。(c++11之后才能保证这样写的正确性,因为之前没有规定多线程环境下对局部static初始化的行为)

Singleton* getInstance()
{  
   static Singleton* singleton = new Singleton();   
   return singleton;
}

饿汉式代码

class Singleton
{
public:
    static Singleton* getInstance();
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
private:
    static Singleton* singleton;
    Singleton(){};
};
Singleton* Singleton::singleton = new Singleton();
Singleton* Singleton::getInstance()
{
    return singleton;
}

使用场景

一、为整个项目提供一个全局访问点,它可能会参与到各个类的行为中,比如游戏引擎中的控制器。

二、创建对象需要消耗过多资源的类,比如说访问io、数据库操作(需要初始化时连接数据库)。


个快快 2018年11月11日 天气 晴

REMARKS

© 2018 MoodBlog 0.2 个快快 作品 | 参考主题: mathilda by fuzzz. | 鲁ICP备16047814号