不得不说的创建型模式-单例模式

news2025/1/30 16:25:53

单例模式是创建型模式的一种,它的作用是确保一个类只有一个实例,并提供全局访问点。单例模式通常用于管理共享资源,如配置文件、数据库连接池等,它可以保证这些资源只被创建一次,并且可以被全局共享。

下面是一个使用C++实现单例模式的示例代码:

#include <iostream>
using namespace std;

class Singleton {
private:
    // 私有静态成员变量,用于保存唯一实例的指针
    static Singleton* instance;

    // 私有构造函数,防止外部创建新的实例
    Singleton() {
        cout << "创建单例对象" << endl;
    }

public:
    // 公有静态成员函数,用于获取唯一实例的指针
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }

    // 公有成员函数,用于测试单例对象的调用次数
    void test() {
        cout << "调用单例对象的test方法" << endl;
    }
};

// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;

int main() {
    // 获取单例对象
    Singleton* singleton1 = Singleton::getInstance();
    // 调用单例对象的test方法
    singleton1->test();

    // 获取单例对象
    Singleton* singleton2 = Singleton::getInstance();
    // 调用单例对象的test方法
    singleton2->test();

    // 判断singleton1和singleton2是否为同一个对象
    if (singleton1 == singleton2) {
        cout << "singleton1和singleton2是同一个对象" << endl;
    } else {
        cout << "singleton1和singleton2不是同一个对象" << endl;
    }

    return 0;
}

在上面的代码中,我们使用静态成员变量instance来保存唯一实例的指针,并使用静态成员函数getInstance来获取该指针。在getInstance方法中,我们判断instance是否为nullptr,如果是,则创建新的实例并赋值给instance;否则,直接返回instance。这样就可以保证整个程序中只有一个Singleton对象。

在实际应用中,单例模式可以用来管理各种共享资源,如数据库连接、文件系统、线程池等。在实现时,我们可以使用懒汉式单例模式,即在第一次调用getInstance方法时创建单例对象,以避免浪费系统资源。如果需要在多线程环境下使用单例模式,我们需要采用线程安全的实现方式,如双检锁单例模式或者使用C++11中的std::call_once函数。

单例模式是一种非常有用的设计模式,它可以确保一个类只有一个实例,并提供全局访问点。在实现时,我们需要注意线程安全性和懒加载性,以提高系统的性能和可靠性。

除了上述提到的资源管理外,单例模式还可以在许多其他场景中使用,例如日志记录器、窗口管理器、缓存等。下面分别介绍几个实际应用场景:

  1. 日志记录器

在大型软件系统中,日志记录是一项非常重要的工作。我们可以使用单例模式创建一个全局的日志记录器,以便在整个系统中都可以方便地访问和使用。这样做还可以避免由于多个日志记录器同时工作导致的日志信息不一致问题。

2.窗口管理器

在图形界面应用程序中,窗口管理器是一个重要的组件,它可以负责创建、显示和管理各种窗口。我们可以使用单例模式创建一个全局的窗口管理器,以便在整个系统中都可以方便地访问和使用。这样做还可以避免由于多个窗口管理器同时工作导致的窗口状态不一致问题。

3.缓存

在许多应用程序中,缓存是一项重要的技术,它可以减少系统的响应时间并提高性能。我们可以使用单例模式创建一个全局的缓存管理器,以便在整个系统中都可以方便地访问和使用。这样做还可以避免由于多个缓存管理器同时工作导致的缓存状态不一致问题。

总的来说,单例模式可以在许多不同的应用场景中使用,它可以确保一个类只有一个实例,并提供全局访问点。在实际应用中,我们需要根据具体的需求来设计和实现单例模式,以提高系统的性能和可靠性。

在实际编程中,实现单例模式的方式有多种,下面我们来看一种基于饿汉式的实现方法:

class Singleton {
private:
    static Singleton* instance;

    Singleton() {} // 将构造函数设置为私有,确保只能通过GetInstance()函数获取实例

public:
    static Singleton* GetInstance() {
        return instance;
    }

    void DoSomething() {
        // 实现单例模式的具体逻辑
    }
};

Singleton* Singleton::instance = new Singleton(); // 类的静态成员变量必须在类外进行初始化

int main() {
    Singleton* s1 = Singleton::GetInstance();
    Singleton* s2 = Singleton::GetInstance();
    assert(s1 == s2); // 验证s1和s2是否是同一个实例

    s1->DoSomething(); // 使用单例模式
    s2->DoSomething(); // 使用单例模式

    return 0;
}

在这个实现方法中,我们将类的构造函数设置为私有,这样外部就无法通过创建对象的方式来获取实例。然后我们定义了一个静态成员变量instance,它是一个指向Singleton对象的指针。在类的实现中,我们在静态成员变量instance上执行了一个new操作,来创建Singleton对象,并将其赋值给instance。

由于静态成员变量instance是一个全局变量,因此在程序启动时就会被创建,从而实现了饿汉式的单例模式。在GetInstance()函数中,我们只需要返回静态成员变量instance的值即可。这样,我们就可以通过Singleton::GetInstance()函数来获取Singleton的唯一实例了。

需要注意的是,饿汉式的单例模式在程序启动时就会被创建,因此会占用一定的内存空间。如果我们的应用程序需要创建多个单例模式,那么这种实现方法可能会导致内存浪费的问题。此时,我们可以考虑使用懒汉式的单例模式来避免这个问题。

除了饿汉式之外,懒汉式也是实现单例模式的一种常用方式。懒汉式的单例模式是在需要使用时才创建单例对象,避免了饿汉式的内存浪费问题。下面是一个基于懒汉式的单例模式的实现方法:

class Singleton {
private:
    static Singleton* instance;

    Singleton() {} // 将构造函数设置为私有,确保只能通过GetInstance()函数获取实例

public:
    static Singleton* GetInstance() {
        if (instance == nullptr) { // 如果instance为空,则创建Singleton对象
            instance = new Singleton();
        }
        return instance;
    }

    void DoSomething() {
        // 实现单例模式的具体逻辑
    }
};

Singleton* Singleton::instance = nullptr; // 类的静态成员变量必须在类外进行初始化

int main() {
    Singleton* s1 = Singleton::GetInstance();
    Singleton* s2 = Singleton::GetInstance();
    assert(s1 == s2); // 验证s1和s2是否是同一个实例

    s1->DoSomething(); // 使用单例模式
    s2->DoSomething(); // 使用单例模式

    return 0;
}

在这个实现方法中,我们同样将构造函数设置为私有,确保只能通过GetInstance()函数获取实例。与饿汉式不同的是,在GetInstance()函数中,我们首先判断静态成员变量instance是否为空。如果instance为空,则创建一个新的Singleton对象并将其赋值给instance。否则,直接返回instance的值即可。

懒汉式的单例模式具有延迟加载的特性,只有在需要使用时才会创建对象,避免了饿汉式的内存浪费问题。但需要注意的是,如果多个线程同时调用GetInstance()函数,可能会导致多个Singleton实例被创建。为了避免这个问题,我们可以使用双检锁机制或者静态局部变量等方式来保证线程安全。

双检锁机制是指在懒汉式的单例模式中,使用两个if语句来确保线程安全,从而避免多个线程同时创建多个实例的问题。下面是一个使用双检锁机制实现的懒汉式单例模式的例子:

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mutex; // 用于实现线程安全

    Singleton() {} // 将构造函数设置为私有,确保只能通过GetInstance()函数获取实例

public:
    static Singleton* GetInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mutex); // 使用锁保证线程安全
            if (instance == nullptr) { // 双检锁机制
                instance = new Singleton();
            }
        }
        return instance;
    }

    void DoSomething() {
        // 实现单例模式的具体逻辑
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;

int main() {
    Singleton* s1 = Singleton::GetInstance();
    Singleton* s2 = Singleton::GetInstance();
    assert(s1 == s2);

    s1->DoSomething();
    s2->DoSomething();

    return 0;
}

在这个实现方法中,我们使用了一个静态的互斥量mutex来保证GetInstance()函数的线程安全。当一个线程进入GetInstance()函数时,会先尝试获取互斥量mutex的锁,如果获取成功,则判断instance是否为空。如果instance为空,则创建一个新的Singleton对象并将其赋值给instance。在instance被创建后,释放互斥量mutex的锁,让其他线程可以继续访问GetInstance()函数。

这种实现方式可以避免多个线程同时创建多个实例的问题,同时也避免了饿汉式的内存浪费问题。不过需要注意的是,在使用互斥量mutex时需要考虑到性能问题,因为每次调用GetInstance()函数时都会涉及到锁的竞争和释放操作,可能会影响程序的性能。

除了双检锁机制之外,静态局部变量也是实现懒汉式单例模式的一种常用方式。静态局部变量的特点是在程序第一次进入这个函数时被初始化,避免了多线程竞争和锁的开销。下面是一个使用静态局部变量实现懒汉式单例模式的例子:

class Singleton {
private:
    Singleton() {} // 将构造函数设置为私有,确保只能通过GetInstance()函数获取实例

public:
    static Singleton* GetInstance() {
        static Singleton instance; // 静态局部变量
        return &instance;
    }

    void DoSomething() {
        // 实现单例模式的具体逻辑
    }
};

int main() {
    Singleton* s1 = Singleton::GetInstance();
    Singleton* s2 =Singleton::GetInstance();
    assert(s1 == s2);
    s1->DoSomething();
    s2->DoSomething();

    return 0;
}


在这个实现方法中,我们将Singleton对象作为静态局部变量在GetInstance()函数中定义,这样它会在程序第一次调用GetInstance()函数时被初始化。由于静态局部变量只会被初始化一次,所以不会出现多个线程同时创建多个实例的问题。

静态局部变量的实现方式比双检锁机制更加简单,不需要使用锁来保证线程安全,同时也避免了饿汉式的内存浪费问题。不过需要注意的是,在使用静态局部变量时需要考虑到线程安全的问题,因为静态局部变量只会被初始化一次,如果多个线程同时访问GetInstance()函数,可能会导致初始化顺序的问题,从而出现程序异常。

单例模式的实际应用非常广泛,例如在GUI程序中,需要保证只有一个主窗口,可以使用单例模式来实现;在多线程程序中,需要共享一个全局变量或对象,可以使用单例模式来实现;在数据库连接池中,需要保证只有一个数据库连接池对象,可以使用单例模式来实现。通过使用单例模式,我们可以方便地管理和控制全局唯一的对象,避免了重复创建对象的开销和资源浪费,提高了程序的性能和效率。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/433559.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI 智能会有自主意识吗?会不会伤害人?

随着科技的高速发展&#xff0c;人工智能已逐渐融入我们的日常生活。从智能家居设备到自动驾驶汽车&#xff0c;人工智能的应用领域越来越广泛。然而&#xff0c;在这个趋势背后&#xff0c;我们面临着一个极具争议的问题&#xff1a;人工智能是否会觉醒自我意识&#xff1f;我…

程序员阿里三面无理由挂了,被HR一句话噎死,网友:这可是阿里啊

进入互联网大厂一般都是“过五关斩六将”&#xff0c;难度堪比西天取经&#xff0c;但当你真正面对这些大厂的面试时&#xff0c;有时候又会被其中的神操作弄的很是蒙圈。 近日&#xff0c;某位程序员发帖称&#xff0c;自己去阿里面试&#xff0c;三面都过了&#xff0c;却被…

近期遇到的vscode 插件开发的问题,when表达式,正则匹配路径

前言 最近在修改dbt插件的时候&#xff0c;遇到了几个比较奇怪的问题&#xff0c;猜测应该是因为跟新了VSCode导致的。 这里稍微记录一下&#xff0c;如果能帮助其他的同学&#xff0c;那就太值啦。 when 正则表达式 之前有在packgae.json 中使用 when 的正则表达式&#xf…

文章修改润色软件-中文文章自动润色

在今天这个信息爆炸的时代&#xff0c;写作已经成为了生活和工作中不可或缺的一部分。无论是企业宣传材料、项目报告、还是日常沟通&#xff0c;我们都需要写作来表达自己的意见和观点。但是&#xff0c;对于大多数人来说&#xff0c;写作带来的不仅仅是创作的乐趣&#xff0c;…

Nacos 1.4.x 升级至 2.x 详细步骤及遇到的问题

此前使用的nacos版本是1.4.5&#xff0c;现在nacos最新版本为2.2.2&#xff0c;且修复了旧版本的一些安全问题&#xff0c;下面把详细的升级步骤记录一下&#xff0c;大家一起学习。主要参照了nacos官方升级文档&#xff1a;https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-up…

MongoDB 分片集群架构中的分片策略

一、分片集群架构 1-1、分片简介 分片&#xff08;shard&#xff09;是指在将数据进行水平切分之后&#xff0c;将其存储到多个不同的服务器节点上的一种扩展方式。分片在概念上非常类似于应用开发中的“水平分表”。不同的点在于&#xff0c;MongoDB本身就自带了分片管理的能…

【Linux】基于单例模式懒汉实现方式的线程池

目录 一、LockGuard.hpp 二、Task.hpp 三、Thread.hpp 四、ThreadPool.hpp 一、LockGuard.hpp #pragma once #include <iostream> #include <pthread.h> class Mutex//锁的对象 { public:Mutex(pthread_mutex_t* lock_pnullptr):_lock_p(lock_p){}~Mutex(){}v…

设计模式-看懂UML类图和时序图

这里不会将UML的各种元素都提到&#xff0c;只讲类图中各个类之间的关系&#xff1b; 能看懂类图中各个类之间的线条、箭头代表什么意思后&#xff0c;也就足够应对 日常的工作和交流&#xff1b; 同时&#xff0c;应该能将类图所表达的含义和最终的代码对应起来&#xff1b;1.…

Qt音视频开发39-海康sdk回调拿到数据GPU绘制的实现

一、前言 采用海康的sdk做开发&#xff0c;最简单最容易的方式就是传入句柄&#xff08;windows和linux都支持/很多人以为只有windows才支持&#xff09;即可&#xff0c;这种方式不用自己处理绘制&#xff0c;全部交给了sdk去处理&#xff0c;所以cpu的占用是最低的&#xff…

ERTEC200P-2 PROFINET设备完全开发手册(8-1)

8.1 IRT通讯实验 这里我们使用APP3 IsoApp&#xff0c;修改源代码usrapp_cfg.h的宏为 #define EXAMPL_DEV_CONFIG_VERSION 3 使能App3&#xff0c;对应的主程序为“usriod_main_isoapp.c” 编译后下载运行。打开4.2建立的TIA项目&#xff0c;添加等时模式组织块&#xff0c…

SAS学习第3章:试验数据处理的心决

sas中数据的输入格式一般分为2种&#xff0c;一种是直接输入&#xff0c;另一种是循环输入。input 后跟几个变量名&#xff0c;数据卡cards就要据此逐次处理&#xff0c;且一定是倍数关系。 1.直接输入在自变量及数据较少的情况下较好使用。 例&#xff1a; 甲、乙、丙三个奶…

代码随想录_二叉树_leetcode105 106

leetcode105. 从前序与中序遍历序列构造二叉树 105. 从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入…

android sdl编译

SDL&#xff08;Simple DirectMedia Layer&#xff09;是一套开放源代码的跨平台多媒体开发库&#xff0c;使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数&#xff0c;让开发者只要用相同或是相似的代码就可以开发出跨多个平台。 1 下载SDL源码 http://www.libsd…

后缀数组的应用:最长公共子串

题目描述 假设 str1 长度为 N N N&#xff0c;str2 长度为 M M M&#xff0c;求 str1 和 str2 的最长公共子串。 思路分析 示例&#xff1a;str1 “12abcd456”, str2 “7abcd89”&#xff0c;则str1和str2的最长公共子串为 abcd。 注意&#xff0c;子串是连续的。 动…

二叉搜索树专题

二叉搜索树专题 特性篇LeetCode 230. 二叉搜索树中第K小的元素解题思路代码实现LeetCode 538. 把二叉搜索树转换为累加树解题思路代码实现 基操篇LeetCode 98. 验证二叉搜索树解题思路代码实现LeetCode 700. 二叉搜索树中的搜索代码实现LeetCode 701. 二叉搜索树中的插入操作解…

总结826

学习目标&#xff1a; 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 高等数学&#xff1a;复习12讲二元积分&#xff0c;第12讲习题&#xff0c;做了17道题 英语&#xff1a;早上背单词&am…

CAXA 3D 实体设计2020 caxa电子图板2020 64位/32位 详细安装方法

CAXA实体设计2016是国内软件公司根据美国最新的专利技术和多年在CAD/CAM领域积累的经验打造的专业3D模型设计软件&#xff0c;具有国际先进水平&#xff0c;支持创新模式和工程模式。创新模式将可视化自由设计与精准设计相结合&#xff0c;使产品设计跨越了传统参数化CAD软件的…

PHP项目——外卖点餐系统后台管理解析

项目介绍 系统基于总部多门店的连锁模式&#xff0c;拥有门店独立管理后台&#xff0c;支持总部定价和门店定价、LBS定位点餐&#xff0c;可堂食可外卖&#xff0c;适用于茶饮的外卖点餐场景&#xff0c;搭建自己的一点点、奈雪、喜茶点餐系统。 平台后台 1.商品 对门店总商…

取消调休?这个公司好像知道员工要什么...

今年的五一小长假3天变5天&#xff0c;比以往多2天&#xff0c;但是为了多出来的这两天&#xff0c;前一个周末的周日&#xff0c;也就是本周的周日4月23日&#xff0c;要正常上班一天。 五一回来后的5月6日&#xff0c;也就是回来后的那个周六&#xff0c;也要上班&#xff0…

无线蓝牙耳机哪款音质好?目前音质最好的无线蓝牙耳机推荐

现如今&#xff0c;蓝牙耳机已经是一个非常实用且常见的数码产品了&#xff0c;不少人喜欢戴着蓝牙耳机听歌&#xff0c;玩游戏。一款音质好的蓝牙耳机不止能听个响&#xff0c;还能给人极致的听觉享受。在此&#xff0c;我来给大家分享几款目前音质最好的无线蓝牙耳机&#xf…