alin的学习之路:设计模式之单例模式

alin的学习之路:设计模式之单例模式

单例模式,顾名思义就是类只有一个实例对象,并且她自己负责创建自己的对象,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式的优点:

  • 在内存中只有一个对象, 节省内存空间
  • 避免频繁的创建销毁对象,可以提高性能
  • 避免对共享资源的多重占用
  • 可以全局访问

c++开发的时候, 一般情况下不允许使用全局变量, 因为这样会破坏类的封装, 写一个单例模式的类来代替全局变量

1. 如何实现一个单例

/*
保证类的对象只有一个:
	- 创建类对象使用的构造函数 -> 需要将构造变为私有函数
	- 可以基于一个对象拷贝出另一个对象 -> 需要将拷贝构造函数变为私有
	- 不能在外部调用这个构造和拷贝构造, 对象从哪儿来呢? -> 需要在类的内部通过构造函数创建出一个实例对象
	- 类的成员变量不允许直接在类外部访问 -> 私有成员变量
	- 私有成员变量需要提供一个公共成员函数进行访问 -> 普通的类成员函数必须通过类对象来调用
		- 现在没有对象(在类的外部无法创建), 因此需要通过类名来调用这个成员函数 -> 这种函数是静态函数
		- 需要在静态函数来访问私钥的类对象 -> 在静态函数中只能访问静态的成员变量 -> 类的对象也是静态的
*/

class Test
{
public:
    // 构造函数
    // 默认析构函数
    // 拷贝构造函数
}
// 保证构造和拷贝构造不能被外部调用, 所有应该设置他们的属性为私有的
class Test
{
public:    
    // 默认析构函数    
    static Test* getInstance()
    {
        return &m_t;
    }
    
private:
    // 构造函数
    Test();
    // 拷贝构造函数
    Test(const Test &t);
    // 提供一个唯一的实例对象, 属于类
    // 这个对象是私有的不能直接访问, 而且的静态, 需要提供一个静态函数进行对象的访问
    static Test m_t; 
}
// 实现单例类的方式
// 1. 懒汉模式: 单例对象只有被使用的时候才被创建
// 2. 饿汉模式: 单例对象在没有被使用之前被创建

2. 懒汉模式

懒汉模式,顾名思义就是实例在用到的时候才去创建,“比较懒”,用的时候才去检查有没有实例,如果有则返回,没有则新建。使用过程中有线程安全的问题

  • 加锁
//
// test.cpp
//
Mutex mutex;
Test* Test::m_test = NULL;
Test* Test::getInstance()
{
    // 如果对象已经存在了, 多个线程访问单例对象是线性的, 不是并行的
    // 不管单例对象存在还是不存在, 对对象的访问都是线性的(顺序访问), 效率低
    // 如果对象是存在的, 对象是可以并行访问的(优化思路)
    mutex.lock();
    if(m_test == NULL)
    {
        m_test = new Test();
    }
    m_mutex.unlock();
    return m_test;
}
  • 双重检查和锁搭配使用
// 版本3: 提高效率, 提高了第二波(包括2)后边线程的访问效率
// 双重检查锁
//
// test.cpp
//
Mutex mutex;
Test* Test::m_test = NULL;
Test* Test::getInstance()
{
    // 如果单例对象已经存在, 直接并行访问单例对象
    // 如果单例对象不存在, 多个线程进入到第一个if中, 顺序访问互斥锁
    if(m_test == NULL)
        mutex.lock();
        if(m_test == NULL)
        {
            m_test = new Test();
        }
        m_mutex.unlock();
	}
    return m_test;
}
  • 使用c++的语法中的线程同步的机制
// 版本4: 要求编译器必须支持c++11
//
// test.h
//
class Test
{
public:    
    
    static Test* getInstance();
private:
    // 构造函数
    Test();
    // 拷贝构造函数
    Test(const Test &t);
}

//
// test.cpp
//
Test* Test::getInstance()
{
    // 静态的局部变量
	static Test* m_test = new Test();    //底层已经实现了线程的同步,不需要再考虑
    return m_test;
}

3. 饿汉模式

饿汉模式,从名字上也很好理解,就是“比较勤”,实例在初始化的时候就已经建好了,不管你有没有用到,都先建好了再说。好处是没有线程安全的问题,坏处是浪费内存空间

推荐的方式。

// 方式1
//
// test.h
//
class Test
{
public:    
    // 默认析构函数 
    static Test* getInstance();
private:
    // 构造函数
    Test();
    // 拷贝构造函数
    Test(const Test &t);
    static Test *m_test;
}

//
// test.cpp
//
// 实例化单例对象
Test* Test::m_test = new Test();
Test* Test::getInstance()
{
    return m_test;
}
// 方式2
//
// test.h
//
class Test
{
public:    
    // 默认析构函数 
    static Test* getInstance();
private:
    // 构造函数
    Test();
    // 拷贝构造函数
    Test(const Test &t);
    static Test m_test;
}

//
// test.cpp
//
// 对象已经被实例化了, 在外部声明一下这个变量就可以了
Test Test::m_test;

Test* Test::getInstance()
{
    return &m_test;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值