单例模式

简介

  • 单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”

  • 单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。

应用

  • 一些资源管理器需要设计成单例模式。

    • 当使用打印机时,打印机一次只能处理一个打印任务。另一个访问任务(另一个实例)被拒绝访问。
    • 传真机一次只能传送一份传真作业。另一份传真作业(另一个实例)被拒绝传送。
  • 这些资源管理需要满足的条件

    • 资源管理器构件必须只有一个实例。
    • 它们必须自行初始化。
    • 允许整个系统访问自己。

要点

  • 某个类只能有一个实例

  • 它必须自行创建这个实例

  • 它必须自行向整个系统提供这个实例

实现

  • 单例模式的类只提供私有的构造函数。构造函数若定义为公有,则任意对象均可实例化。

  • 类定义中含有一个该类的静态私有对象。静态变量只初始化一次,在类外初始化。静态数据成员只有一个复制品。

  • 类提供了一个静态公有函数用于创建或获取它本身的静态私有对象。静态成员函数属于整个类,通过类名::静态公有函数访问。

注意

  • 构造函数可设置为受保护权限以允许子类派生。

  • 单例模式只考虑对象创建的管理,没有考虑对象销毁的管理,就支持垃圾回收的平台和对象的开销来讲,我们一般没必要对其销毁进行特殊的管理。但我们需要注意资源回收问题。

单例模式的三种形式

  • 懒汉式

  • 饿汉式

  • 双重锁形式

懒汉式

  • 在使用时初始化,存在多线程安全问题。

  • 并发线程的次序会使过程受到影响。

class S
{   
private:
    S() {}  // 私有的构造函数

public:
    static S* instrance();  //静态成员函数,提供访问接口和实例化对象
    static void destory();  //不再需要该实例时进行资源释放

private:
    static S *s;  // 对象指针,存在内存泄漏问题
};

S *S::s = nullptr;   //先初始化为nullptr,使用时实例化

S* S::instrance() {
    if (s == nullptr)
        s = new S();
    return s;
}
void S::destory() {
    if (s != nullptr) {
        delete s;
        s = nullptr;
    }
}

饿汉式

  • 直接实例化,多线程使用时处于安全状态。
class S
{   
private:
    S() {}  // 私有的构造函数

public:
    static S* instrance();  //静态成员函数,提供访问接口和实例化对象
    static void destory();  //不再需要该实例时,需要显式进行资源释放

private:
    static S *s;  // 对象指针,存在内存泄漏问题
};

S *S::s = new S();   //直接实例化

S* S::instrance() {
    return s;
}
void S::destory() {
    if (s != nullptr) {
        delete s;
        s = nullptr;
    }
}

双重锁形式

  • 双重检查锁DCL,主要防护懒汉式的线程安全问题。
class S
{   
private:
    S() {}  // 私有的构造函数

public:
    static S* instrance();  //静态成员函数,提供访问接口和实例化对象
    static void destory();  //不再需要该实例时进行资源释放

private:
    static S *s;  // 对象指针,存在内存泄漏问题
    static mutex m;  // 双重检查锁DCL
};

S *S::s = nullptr;   //先初始化为nullptr,使用时实例化
mutex S::m;

S* S::instrance() {
    lock_guard<mutex> lock(m);
    if (s == nullptr)
        s = new S();
    return s;
}
void S::destory() {
    if (s != nullptr) {
        delete s;
        s = nullptr;
    }
}

显示释放

  • 我们定义了静态的成员函数进行显式的资源释放。具体为:当不再需要该实例时,调用该静态成员函数,销毁对象。

  • 存在问题:忘记销毁???

void S::destory() {
    if (s != nullptr) {
        delete s;
        s = nullptr;
    }
}

隐式

class S
{   
private:
    S() {}  // 私有的构造函数

public:
    static S* instrance();  //静态成员函数,提供访问接口和实例化对象

private:
    static S *s;  // 对象指针,存在内存泄漏问题
    static mutex m;  // 双重检查锁DCL
    class Garbage_Collection {
        ~Garbage_Collection()
        {
            if (s != nullptr) {
                delete s;
                s = nullptr;
            }
        }
        static Garbage_Collection g;
    };
};

S *S::s = nullptr;   //先初始化为nullptr,使用时实例化
mutex S::m;
S::Garbage_Collection   S::Garbage_Collection::g;  //静态变量会在程序结束时释放,静态对象会调用析构

S* S::instrance() {
    lock_guard<mutex> lock(m);
    if (s == nullptr)
        s = new S();
    return s;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值