设计模式之单例模式

来源:互联网 发布:如何查询淘宝购买记录 编辑:程序博客网 时间:2024/06/15 10:42

作用:保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象
构造图如下:
这里写图片描述
为什么需要单例模式:
1、在多个线程之间,比如初始化一次socket资源
2、在整个程序空间使用全局变量,共享资源
3、大规模系统中,为了性能的考虑,需要节省对象的创建时间
实现步骤:
1、构造函数私有化
2、提供一个全局的静态方法(全局访问点)
3、在类中定义一个静态指针,指向本类的变量的静态变量指针
单例模式分类及实现:

  • 懒汉式:
    懒汉式的特点是延迟加载,比如配置文件,采用懒汉式的方法,顾名思义,懒汉么,很懒的,配置文件的实例直到用到的
    时候才会加载。。。。。。
#include <iostream>using namespace std;// 懒汉式单例class UserManage{private:    UserManage(){}public:    static UserManage* GetInstanc()    {        if (m_instance == NULL)        {            m_instance = new UserManage;        }        handle_count++;        return m_instance;    }    static void Release()    // 释放句柄    {        handle_count--;        if(m_instance != NULL && handle_count == 0)        {            delete m_instance;            m_instance = NULL;        }    }private:    static UserManage *m_instance;     // 对象指针,对象句柄    static int handle_count;           // 引用计数};// 静态变量在类的外部进行初始化UserManage *UserManage::m_instance = NULL;int UserManage::handle_count = 0;void func(){    UserManage *um1 = UserManage::GetInstanc();    // ......    UserManage::Release();}int main1(){    // 获取对象指针    UserManage *um1 = UserManage::GetInstanc();    UserManage *um2 = UserManage::GetInstanc();    if(um1 == um2)    {        cout << "是同一个对象" << endl;    }    else    {        cout << "不是同一个对象" << endl;    }    UserManage::Release();     // 释放    return 0;}/*类中存放两个静态变量,一个是对象句柄,一个是计数常量,定义好后必须在类外部进行初始化,这是类的属性。还有两个函数,一个是获取句柄,如果句柄为空,则new一个新的句柄,并且计数加1,然后返回句柄;还有一个是释放句柄,首先计数减一,然后delete句柄并置为空防止出现野指针。懒汉式是当你使用时,他才会创建新的句柄。*/

懒汉式加锁的情况:
由于懒汉式为多行语句,所以在线程运行中可能会造成中断,生成多个对象的情况。
为了提高代码的高效性,所以进行了加锁以及双重判断的情况
第一重判断,为当不存在该对象时,则增加加锁代码块,保证代码块中语句不中断
第二重判断,如果对象值为null,新建这个对象,提高代码的高效性。
实例:

#include <iostream>#include <pthread.h>using namespace std;// 懒汉式单例class UserManage{private:    UserManage()    {        printf ("构造函数被调用\n");        sleep(5);    }public:    static UserManage* GetInstance()    {        if (m_instance == NULL)              // 增加一次判断,避免频繁的上锁与解锁        {            pthread_mutex_lock(&mutex);      // 上锁            if (m_instance == NULL)            {                m_instance = new UserManage;            }            pthread_mutex_unlock(&mutex);    // 解锁        }        handle_count++;        return m_instance;    }    static void Release()    // 释放句柄    {        pthread_mutex_lock(&mutex);      // 上锁        handle_count--;        if(m_instance != NULL && handle_count == 0)        {            delete m_instance;            m_instance = NULL;        }        pthread_mutex_unlock(&mutex);    // 解锁    }    static void *func(void *v)  // void *func(UserManage *const this, void *v)    {    }    void run()    {        pthread_t id;        pthread_create(&id, NULL, func, NULL);    }private:    static pthread_mutex_t  mutex;     // 对象指针锁    static UserManage *m_instance;     // 对象指针,对象句柄    static int handle_count;           // 引用计数};// 静态变量在类的外部进行初始化UserManage *UserManage::m_instance = NULL;int UserManage::handle_count = 0;pthread_mutex_t  UserManage::mutex = PTHREAD_MUTEX_INITIALIZER;   // 对锁进行初始化void* func(void *v){    UserManage* um = UserManage::GetInstance();    // .......    // UserManage::Release();}int main(){/*    pthread_t id;    for (int i = 0; i < 10; i++)    {           pthread_create(&id, NULL, func, NULL);        pthread_detach(id);           // 线程分离    }       pthread_exit(NULL);     // 主线程退出,不影响其他线程运行*/    pthread_t id[10];    for (int i = 0; i < 10; i++)    {           pthread_create(&id[i], NULL, func, NULL);    }       for (int i = 0; i < 10; i++)    {           pthread_join(id[i], NULL);    }       return 0;}
  • 饿汉式:
    饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,那么饿汉式就是“空间换时间”,因为一开始就创建了实例,所以每次用到的之后直接返回就好了。
#include <iostream>using namespace std;// 饿汉式单例class UserManage{private:    UserManage(){}public:    static UserManage* GetInstanc()    {        handle_count++;        return m_instance;    }    static void Release()    // 释放句柄    {        handle_count--;        if(m_instance != NULL && handle_count == 0)        {            delete m_instance;            m_instance = NULL;        }    }private:    static UserManage *m_instance;     // 对象指针,对象句柄    static int handle_count;           // 引用计数};// 静态变量在类的外部进行初始化UserManage *UserManage::m_instance = new UserManage;int UserManage::handle_count = 0;void func(){    UserManage *um1 = UserManage::GetInstanc();    // ......    UserManage::Release();}int main(){    // 获取对象指针    UserManage *um1 = UserManage::GetInstanc();    UserManage *um2 = UserManage::GetInstanc();    if(um1 == um2)    {        cout << "是同一个对象" << endl;    }    else    {        cout << "不是同一个对象" << endl;    }    UserManage::Release();     // 释放    return 0;}/*饿汉式和懒汉式代码上最直接的区别就是饿汉式句柄生成时就已经分配好空间,而懒汉式则是在调用获取句柄的函数中才分配空间。*/

总结一下,两种方案的构造函数和公用方法都是静态的(static),实例和公用方法又都是私有的(private)。但是饿汉式每次调用的时候不用做创建,直接返回已经创建好的实例。这样虽然节省了时间,但是却占用了空间,实例本身为static的,会一直在内存中带着。懒汉式则是判断,在用的时候才加载,会影响程序的速度。最关键的是,在并发的情况下,懒汉式是不安全的。如果两个线程,我们称它们为线程1和线程2,在同一时间调用getInstance()方法,如果线程1先进入if块,然后线程2进行控制,那么就会有两个实例被创建。
比较:
饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的
推荐使用第一种
从实现方式来讲他们最大的区别就是懒汉式是延时加载,
他是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,

原创粉丝点击