单列模式详讲

本文详细介绍了设计模式中的单列模式,包括其定义、应用场景、如何设计单列类以及代码实现,强调了线程安全和资源管理的重要性。单例模式确保类只有一个实例,并提供全局访问点,常用于控制资源的访问,如任务管理器。文章探讨了饿汉模式和懒汉模式的实现及优缺点,提出了双检查机制和内存珊栏优化。最后,总结了单例模式的优缺点和适用场景。
摘要由CSDN通过智能技术生成

一、设计模式简介

(1)什么是设计模式:
设计模式是一套被反复使用,多数人知晓的、经过分类编目的、代码设计的总结,使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性。
(2)设计模式的分类:

  • 按照目的可分为三类:

创建型模式,结构型模式,行为型模式;

  • 按照范围,即模式主要处理类之间的关系还是对象之间的关系分为

类模式、对象模式

(3)设计模式主要被广泛应用于面向对象编程;

二、设计模式之单列模式详讲

(1)什么是单列模式
单例模式是一种常用的软件设计模式,也叫单件模式或者单态模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于被外界访问,从而方便对实例个数的控制并节约系统资源如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案

通俗点来说,就是一个类只允许实例化一个对象,那么该对象必然可以在程序的任何地方被访问

(2)为什么要设计单列模式(or单列模式在实际开发中的应用)

最经典也是最容易理解的例子:用windows的都知道,同一时刻只能打开一个任务管理器,不会弹出多个的,为什么呢?因为系统的状态是每时每刻都在变化的,如果你可以同时打开多个任务管理器,而这些管理器显示的内容出现不一致的情况,是不是容易引起用户误解;而如果多个窗口的显示内容一致的话,打开多个窗口是不是很浪费资源;单例模式就是为了解决这种问题而产生的,当前类只允许你拥有一个真实的对象,如果你继续申请,依然返回同一个对象;

(3)如何设计单列类
从上面的单列模式的定义我们知道,单列模式的要求就是设计一个单列类,该类只能实例化一个对象,且该对象可以在一个程序中的任意地方被访问。

那么我们来思考怎么设计这个单列类,假入我们定义一个全局类的对象变量,没错,这个对象确实可以在程序的任何地方被访问,but,这个类还可以在程序的其他地方创建更多的不同的类对象;这样的话,只是符合了单列模式的对象易于被访问的要求,但是没有符合一个类只能有一个实例的要求;

那么怎么实现这个?方法如下:
(1)要保证该类只能实例化一个对象,那么我们必须将能在类外定义该类对象的所有方法设置为私有,这样的话,就不能在类外定义多个对象;所以首先先把类的构造,拷贝构造,赋值运算符重载统统设为私有;

(2)然后在类的内部定义一个单列类的静态指针成员变量,该成员变量就是单列类的唯一实例;该成员变量定义为私有,符合类的封装性;保证类的安全;

(3)类的唯一实例定义完之后,我们还要定义一个在类外获取该唯一实例的类的方法;该方法设置为公有,对外提供一个获取的接口;该方法也是静态;因为只有类的静态方法才能在类外通过 类名::函数名 的方式调用该方法;

假入不将该获取实例的方法定义为静态的,那么我们就无法获取该实例;因为类的非静态方法在类外进行访问,都需要先定义出该类的对象,然后通过该对象访问;但是在类外获取该的实例的时候,该类的对象还没有定义出来;

(4)
单例模式按照设计模式的分类属于创建型模式对象模式;

单例模式的标准定义:单例模式确保某一个类只有一个实例,而且自行实例化并向整个操作系统提供这个实例,这个类成为单例类,它提供全局的访问方法

(5)单列类的设计要求
1>单例类保证全局只有唯一一个自行创建的实例对象。
2.>单例类提供获取这个唯一实例的接口。

三、代码实现详解

(1)饿汉模式– (线程安全,简洁、高效、不用加锁、但是在某些场景下会有缺陷)

方式一: 定义一个单列类的静态指针成员作为单列类的成员变量,这个成员变量就是单列类的唯一实例;

#include<iostream>
using namespace std;
#include<cassert>
class Singleton
{
public:
// 获取唯一对象实例的接口函数
   static Singleton* GetInstance()
   {
      cout<<"GetInstance"<<endl;
      assert(_sInstance);
      return _sInstance;
   } 
//删除实例对象
  static void DelInstance()
  {
      if (_sInstance)
      {
          delete _sInstance;
          _sInstance=NULL;
      }
  }
  //打印单列类的内容
  void Printf()
  {
      cout<<_data<<endl;
  }
private:
    // 构造函数定义为私有,限制只能在类内创建对象
    Singleton()
        :_data(1)
    {
        cout<<"Singleton"<<endl;
    }
    Singleton(const Singleton& );
    Singleton& operator=(const Singleton&);
    // 指向实例的指针定义为静态私有,这样定义静态成员函数获取对象实例
    static Singleton* _sInstance;
    // 单例类里面的数据
    int _data;
};
//类的静态成员要在类外进行初始化--静态成员在main函数之前初始化
Singleton* Singleton::_sInstance=new Singleton();

void TestSingleton()
{
    //验证在main函数之前单列类对象已经创建---静态成员创建在main之间已经创建好了
    cout<<"main"<<endl;
    //验证单列类创建的对象为同一个对象,即一个单列类只能实例化出一个对象
    Singleton* p1=Singleton::GetInstance();
    Singleton* p2=Singleton::GetInstance();
    p1->Printf();
    p2->Printf();
    cout<<(p1==p2)<<endl;

    //3.验证在单列类在类外无法实例化出其他对象----私有构造,私有拷贝构造,私有赋值运算符重载的作用
    //Singleton s1;//调用构造函数---不行
    //Singleton s2(p1);//调用拷贝构造函数---不行
    //Singleton s1=p2;//调用赋值运算符重载函数---不行
}
int main()
{
    TestSingleton();
    return 0;
}

方式二:直接在获取唯一实例的成员方法中定义一个局部静态单列类对象;其生命周期随程序,且只在第一次进入函数时初始化一次。

#include<iostream>
using namespace std;
#include<cassert>
class Singleton
{
public:
  // 获取唯一
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值