【C++】单例模式

目录

一.创建型设计模式

二.单例模式

1.饿汉式 

2.懒汉式


一.创建型设计模式

        创建型设计模式包括多种不同的模式,每种模式都有其独特的应用场景和解决方案。常见的创建型设计模式包括:

        工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,但是将对象的实际创建推迟到子类中。这样,客户端代码就可以在不必指定具体类的情况下创建对象。

        抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建一系列相关或相互依赖的对象,而不需要指定具体的类。它是工厂方法模式的推广,可以创建一组对象而不是一个对象。

        建造者模式(Builder Pattern):将一个复杂对象的构建过程分离出来,使得相同的构建过程可以创建不同的表示。这样,可以通过不同的建造者组合来构建不同的对象。

        单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式通常用于全局状态管理、资源共享或控制对唯一资源的访问。

        原型模式(Prototype Pattern):通过复制现有对象来创建新对象。原型模式允许我们在不知道对象的具体类型的情况下创建对象,而且对于创建新对象的成本较高的情况下,原型模式可以提高性能。

这些创建型设计模式提供了各种不同的解决方案,可以根据具体的情况选择最合适的模式来创建对象,从而使系统更加灵活、可扩展和易于维护。

 

二.单例模式

        单例模式(Singleton Pattern ,也称为单件模式 ) ,使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例,并提供一个访问它的全局 访问点,该实例被所有程序模块共享。
面向对象编程中,每个对象都应该抽象代表一个设备,并通过对象完成对某个具体设备的管理和维护。 对于有些类只能有一个实例很重要,例如打印机管理器、设备管理器、任务管理器等。

        在单例模式中,类会提供一个静态方法(通常命名为 getInstance()),用于获取类的唯一实例。如果实例不存在,则在第一次调用 getInstance() 方法时创建它,并在后续调用中返回该实例。 

        单例模式的核心思想是确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式通常包含以下步骤:

私有化构造函数:将类的构造函数设置为私有,防止外部直接实例化该类的对象。

静态成员变量:在类中定义一个静态成员变量,用于保存类的唯一实例。

静态成员函数:定义一个静态成员函数(通常命名为 getInstance()),用于获取类的唯一实例。在该函数中实现单例模式的逻辑,包括判断实例是否已创建并进行实例化。

延迟实例化(可选):如果希望在需要时才创建实例,可以在 getInstance() 方法中进行延迟实例化的处理,即在第一次调用时创建实例。

全局访问点:通过静态成员函数提供一个全局访问点来获取类的唯一实例,以确保在程序的任何地方都可以访问该实例。

线程安全处理(可选):在多线程环境下,需要考虑线程安全性。可以通过加锁机制或其他线程同步机制来保证在多线程环境中仍然只创建一个实例。

        最核心的是:

        私有化构造函数--->静态变量储存类的一个实例--->静态成员函数提供创建点

私有化构造函数
class Singleton{
private:
    Singleton(void){...}
    Singleton(const Signleton &that){}
    ...
};
使用静态成员变量维护唯一的单例对象
class Singleton{
private:
    Singleton(void){...}
    Singleton(const Signleton &that){}
    ...
    static Singleton s_instance;
};
Singleton Singleton::s_instance;
定义静态成员函数用于获取单例对象
class Singleton{
private:
    Singleton(void){...}
    Singleton(const Signleton &that){}
    ...
    static Singleton s_instance;
public:
    static Singleton& getInstance(void){
    return s_instance;
    }
};
Singleton Singleton::s_instance;

        单例模式的核心包括私有化构造函数、静态成员变量和静态成员函数,并且通过全局访问点来确保类的唯一实例。在实现时可以选择是否延迟实例化以及是否处理线程安全性。

1.饿汉式 

加载进程时即完成创建(饿), 用不用都创建。

#include <iostream>
using namespace std;

class Signleton{
private:
    int m_i; // 私有成员变量,存储单例对象的状态
    Signleton(int i=0){ // 私有构造函数,确保只能在类内部创建对象
        m_i = i;
    }
    Signleton(const Signleton& that){} // 私有拷贝构造函数,禁止拷贝构造

    static Signleton m_instance; // 静态成员变量,用于保存单例对象的唯一实例

public:
    static Signleton& getInstance(){ // 静态成员函数,提供全局访问点获取单例实例
        return m_instance;
    }

    void print(){ // 公有成员函数,用于打印单例对象的状态
        cout << m_i << endl;
    }
};

Signleton Signleton::m_instance = 111; // 初始化单例对象实例

int main(void){
    Signleton& s1 = Signleton::getInstance(); // 获取单例对象实例的引用
    Signleton& s2 = Signleton::getInstance(); // 再次获取单例对象实例的引用
    Signleton& s3 = Signleton::getInstance(); // 再次获取单例对象实例的引用
    
    //Signleton s4 = 12; //error,因为构造函数是私有的,无法在外部直接实例化对象

    cout << &s1 << endl; // 打印第一个单例对象实例的地址
    cout << &s2 << endl; // 打印第二个单例对象实例的地址
    s1.print(); // 调用单例对象实例的打印函数,打印状态
    s2.print(); // 再次调用单例对象实例的打印函数,打印状态

    return 0;
}

2.懒汉式

用时再创建(懒),不用再销毁。

#include <iostream>
using namespace std;

class Signleton{
private:
    int m_i; // 私有成员变量,存储单例对象的状态
    static int m_count ; // 静态成员变量,记录对象的引用次数
    static Signleton *m_instance; // 静态指针成员,用于保存单例对象的唯一实例

    Signleton(int i = 0){ // 私有构造函数,确保只能在类内部创建对象
        m_i = i;
        cout << "constructor " << endl; // 输出提示信息
    }

    Signleton(const Signleton& that){} // 私有拷贝构造函数,禁止拷贝构造

public:
    static Signleton& getInstance(void){ // 静态成员函数,提供全局访问点获取单例实例
        if(m_instance == NULL){ // 如果实例尚未创建
            m_instance = new Signleton(123); // 在堆上创建新的实例
        }
        m_count++; // 增加引用计数
        return *m_instance; // 返回单例对象实例的引用
    }

    void release(){ // 成员函数,用于减少引用计数并释放实例所占用的内存
        m_count--; // 减少引用计数
        if(m_count == 0){ // 如果引用计数为0
            delete m_instance; // 释放实例所占用的内存
            m_instance = NULL; // 将指针置空
        }
    }

    ~Signleton(){ // 析构函数,输出销毁实例的信息
        cout << "destroy" << endl;
    }
};

Signleton * Signleton::m_instance = NULL; // 初始化单例对象实例指针
int Signleton::m_count = 0; // 初始化引用计数

int main(void){
    Signleton& s1 = Signleton::getInstance(); // 获取单例对象实例的引用
    Signleton& s2 = Signleton::getInstance(); // 再次获取单例对象实例的引用
    Signleton& s3 = Signleton::getInstance(); // 再次获取单例对象实例的引用

    cout << &s1 << " " << &s2 << " " << &s3 << endl; // 打印单例对象实例的地址
    s1.release(); // 释放对实例的引用
    s2.release(); // 释放对实例的引用
    s3.release(); // 释放对实例的引用

    return 0;
}
三.应用场景

饿汉式单例模式
        配置管理器:在程序启动时,可能需要读取配置文件并将配置信息加载到内存中。使用饿汉式单例模式可以确保配置管理器在程序启动时立即可用,而不需要延迟加载。

        日志记录器:在程序运行期间,可能需要记录各种日志信息,如调试信息、错误信息等。使用饿汉式单例模式可以确保日志记录器在程序启动时就被创建,并且在整个程序生命周期内可用。

        数据库连接池:在需要频繁与数据库进行交互的应用中,使用数据库连接池可以提高性能。饿汉式单例模式可以确保数据库连接池在程序启动时就被初始化,并且在整个程序运行期间保持唯一性。

懒汉式单例模式
        延迟加载的资源管理器:有些资源可能只有在需要时才会被加载,例如大型图片、音频文件等。使用懒汉式单例模式可以延迟加载资源管理器,从而节省内存和加载时间。

        对象缓存:在需要频繁创建和销毁对象的场景下,使用懒汉式单例模式可以将对象缓存在内存中,并在需要时返回已缓存的对象,从而提高性能和资源利用率。

        线程池:在多线程应用中,可能需要管理线程池来处理任务。使用懒汉式单例模式可以延迟创建线程池对象,只有在需要时才创建,并且确保线程池的唯一性。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

放牛的守护神_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值