C&C++设计模式——饿汉单例模式

Posted 穿越临界点

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C&C++设计模式——饿汉单例模式相关的知识,希望对你有一定的参考价值。

在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习。我的使命就是过滤掉大量的无效信息,将知识体系化,以短平快的方式直达问题本质,把大家从大海捞针的痛苦中解脱出来。

1 什么是单例模式

单例模式是通过类本身来管理其唯一实例。单例模式就是只实例化一次的模式。这么简单的思想为什么会称之为模式呢?个人认为更重要的原因是让类自我管理的思想使之进入模式行列的。

单例模式根据单例存在的生命周期分为饿汉单例模式和懒汉单例模式。

单例存在于整个软件生命周期的为饿汉单例模式,它在编译阶段就分配了内存,存在于静态数据区。

单例生命周期由程序员控制的为懒汉单例模式,它在程序运行过程中动态分配内存,存在于堆区。

本篇先重点关注比较简单的饿汉单例模式。

2 单例模式的应用场景

单例模式可以应用在打印机、键盘、鼠标等这种唯一性物品对应的类的创建上,这种例子可以推及到虚拟世界(元宇宙)中。

3 类图

单例的类图是最简单的了,如下图所示:

Singleton -_instance +getInstance() -Singleton()

4 C++实现饿汉单例模式

下述是基于模板实现的饿汉单例模式。使用模板可以“一劳永逸”,后面创建任何单例类只需要套用一下模板就可以了。

4.1 实现

饿汉单例模式需要注意的一个点是要将所有和构造相关的接口一律禁止外部使用。

/*Singleton.hpp*/
#ifndef __SINGLETON_H__
#define __SINGLETON_H__
template<typename T>
class Singleton {
public:
    static T& getInstance(); /*定义获取单例接口*/

protected:
    Singleton() {} /*禁止外部调用构造函数*/
    Singleton(const Singleton&) = delete; /*禁止系统自动生成拷贝构造函数*/
    Singleton& operator= (const Singleton) = delete; /*禁止系统生成赋值操作符函数*/
};

template<class T>
T& Singleton<T>::getInstance()
{
    static T instance{}; /*生成单例(唯一的实例)*/
    return instance;
}
#endif

4.2 验证

完成单例的模板编写之后,我们写一个main函数进行测试。

/*main.cpp*/
#include <iostream>
#include "Singleton.hpp"

using namespace std;
class TestClass: public Singleton<TestClass> /*继承单例模板*/
{
public:
    void printMyself() {cout << this << endl; /*打印对象基址*/
};
 
int main(){ 
    /* 比较两次地址打印结果是否一致 */
    TestClass::getInstance().printMyself();
    TestClass::getInstance().printMyself();

    return 0;
}

使用CMake进行编译。

cmake_minimum_required(VERSION 3.16)
project(singleton)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wno-unused-function -Wno-error-unused-variable -g")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function -Wno-error-unused-variable -g")
string(REGEX REPLACE "[-]O2" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
string(REGEX REPLACE "[-]O2" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})

set(SRCS main.cpp)

message(status "Making, please wait ...")

add_executable(singleton ${SRCS})

输出结果如下:

my_path$ ./singleton
0x55a7d1b1e152
0x55a7d1b1e152

我们发现输出的是同一个对象地址,结果符合预期。


5 C语言实现饿汉单例模式

由于用C语言本身不支持面向对象语法,所以使用C语言来进行面向对象编程代码量会稍微多一些。

5.1 实现

单例头文件代码如下:

/*Singleton.h*/
#ifndef __SINGLETON_H__
#define __SINGLETON_H__

#define class struct 

typedef class Singleton_s Singleton;
typedef void (*printMyself_t)(Singleton *this); 

typedef class Singleton_s 
{
//public:
    printMyself_t printMyself;
}Singleton;

extern Singleton *Singleton_getInstance(void);
#endif

单例源文件如下:

/*Singleton.c*/
#include <stdio.h>
#include "singleton.h"

static void printMyself(Singleton *this)
{
    printf("The addr of obj is %p \\n", this);
}
/*使用static修饰,禁止被外部调用*/
static void createSingleton(Singleton *this)
{
    this->printMyself = &printMyself;
}

Singleton *Singleton_getInstance(void)
{
    /*对于单例来说该对象可以定义成全局的,
    从而可以把类内方法中的this指针入参全部省掉,以便简化使用*/
    static Singleton m_singleton = {0}; 

    createSingleton(&m_singleton);
    return &m_singleton;
}

5.2 验证

main文件如下:

#include <stdio.h>
#include "singleton.h"

int main()
{
    Singleton *m_singleton = Singleton_getInstance();
    Singleton *m_singleton1 = Singleton_getInstance();

    /*比对两个对象地址是否一致*/
    m_singleton->printMyself(m_singleton);
    m_singleton1->printMyself(m_singleton1);

    return 0;
}

运行结果如下:

my_path$ ./singleton
The addr of obj is 0x5599698f9018
The addr of obj is 0x5599698f9018

对象地址一致,验证通过。

6 两种语言实现对比

我们发现使用C语言实现饿汉单例模式比使用C++语言语法要更加复杂,但是基本的思想是一样的。

我们通过对比C语言和C++语言的实现能更深入的理解面向对象编程的工作方式,不仅仅是停留在照猫画虎阶段。


恭喜你又坚持看完了一篇博客,又进步了一点点!如果感觉还不错就点个赞再走吧,你的点赞和关注将是我持续输出的哒哒哒动力~~

以上是关于C&C++设计模式——饿汉单例模式的主要内容,如果未能解决你的问题,请参考以下文章

C&C++设计模式——饿汉单例模式

C&C++设计模式——饿汉单例模式

饿汉单例模式 and 懒汉单例模式

深入理解设计模式-单例模式(饿汉单例模式懒汉单例模式双锁单例模式)

单例设计模式

饿汉单例模式实例——取快递