您现在的位置是:首页 >学无止境 >设计模式初探----单例模式网站首页学无止境

设计模式初探----单例模式

back2childhood 2024-06-22 12:01:02
简介设计模式初探----单例模式

概述

单例模式:保证类的实例化对象仅有一个,并提供一个访问他的全局访问点

应用场景

  • 表示文件系统的类,一个操作系统一定是只有一个文件系统,因此文件系统的类的实例有且仅有一个。
  • 打印机打印程序的实例,一台计算机可以连接好几台打印机,但是计算机上的打印程序只有一个,就可以通过单例模式来避免两个打印作业同时输出到打印机。

实现方式

单例模式可以通过全局或者静态变量的形式实现,这样比较简单,但是这样会影响封装性,难以保证别的代码不会对全局变量造成影响。

  • 默认的构造函数、拷贝构造函数、赋值构造函数声明为私有的,这样禁止在类的外部创建该对象;
  • 全局访问点也要定义成 静态类型的成员函数,没有参数,返回该类的指针类型。因为使用实例化对象的时候是通过类直接调用该函数,并不是先创建一个该类的对象,通过对象调用。

不安全的实现方式:
原因:考虑当两个线程同时调用 getInstance 方法,并且同时检测到 instance 是 NULL,两个线程会同时实例化对象,不符合单例模式的要求。

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

懒汉模式

懒汉模式:直到第一次用到类的实例时才去实例化,上面是懒汉实现。

加锁

每次判断实例对象是否为空,都要被锁定,如果是多线程的话,就会造成大量线程阻塞。

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;

class Singleton {
private:
  static pthread_mutex_t mutex;
  static Singleton *instence; // c++11之后static本身就是线程安全的,不需要加锁
  Singleton() {
    pthread_mutex_init(&mutex, NULL);
    cout << "init" << endl;
  }
  Singleton(const Singleton &tmp) {}
  Singleton &operator=(const Singleton &tmp) {}

public:
  static Singleton *getInstence() {
    pthread_mutex_lock(&mutex);	// 防止多个线程同时创建实例
    if (instence == NULL) {
      instence = new Singleton();
    }
    pthread_mutex_unlock(&mutex);
    return instence;
  }
  void fun() { cout << "fun" << endl; }
};
Singleton *Singleton::instence = NULL;
pthread_mutex_t Singleton::mutex;

void test() { Singleton::getInstence()->fun(); }

int main() {
  Singleton::getInstence()->fun();
  thread t(test);
  t.join();
}

输出:

init
fun
fun

内部静态变量

在全局访问点 getInstance 中定义静态实例。

class Singleton{
private:
    static pthread_mutex_t mutex;
    Singleton(){
        pthread_mutex_init(&mutex, NULL);
    }
    Singleton(const Singleton& temp){}
    Singleton& operator=(const Singleton& temp){}
public:
    static Singleton* getInstence(){ 
        static Singleton instence;
        return &instence;
    }
};
pthread_mutex_t Singleton::mutex; 

饿汉模式

类定义的时候就实例化,本身就是线程安全的,不需要加锁

因为饿汉模式在定义类的时候,就会实例化,所以实例会一直占用着内存,而懒汉模式是在使用的时候才会实例化,因此懒汉模式的内存使用效率上会更高。

class Singleton{
private:
    static Singleton* instence;
    Singleton(const Singleton& temp){}
    Singleton& operator=(const Singleton& temp){}
protected:
	 Singleton(){} 
public:
    static Singleton* getInstence(){ 
        return instence;    
    }
};
Singleton* Singleton::instence = new Singleton();
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。