【设计模式 01】单例模式

单例模式,是一种创建型设计模式,他的核心思想是保证一个类只有一个实例(即,在整个应用程序中,只存在该类的一个实例对象,而不是创建多个相同类型的对象),并提供一个全局访问点来访问这个实例(即,其他类只能通过一个,可以是静态方法,来获取到这个唯一实例)。

优势:因为只有一个实例,既避免了多次创建相同的对象,节省了系统资源。多个类,也就是模块之间可以通过单例实例来共享数据;同时方便我们站在全局的角度控制唯一实例的访问(即,可以严格的控制客户怎样访问它、何时访问他);此外,单例模式还允许只在需要时才进行实例化,即所谓的懒加载,以提高程序的性能。

实现一个单例设计模式需要满足以下的基本要求首先,任何外部代码不能够随意创建实例,也就意味着类的构造函数只能私有;其次,任何外部代码也不能够随意访问实例中的任何资源,也就意味着所有的静态实例变量须是私有的;最后,需要设置一个公有的静态方法,以便外部能够获取到实例的内部资源。

单例模式的实现方式有:懒汉式(只有在遇到请求实例时才会创建一个实例,并且如果已经创建过,就会返回已有的实例)、饿汉式(类加载时就已经完成了实例的创建,不管创建的实例在后面会不会使用,先创建再说)等。

在多线程环境下,由于饿汉式在程序启动阶段就完成实例的初始化,因此不存在多个线程同时尝试初始化实例的问题;但是懒汉式中多个线程同时访问 GetInstance() 方法,并且在同一时刻检测到实例没有被创建(只要线程切换足够频繁就有可能发生),就可能会同时创建实例,从而导致多个实例被创建,(好比你和小明都发现家里每米了,在你们没有相互通知的情况下,都会去超市买一袋米,这样就重复购买了,违背了单例模式)这种情况下我们可以采用一些同步机制,例如使用互斥锁来确保在任何时刻只有一个线程能够执行实例的创建。

以下是单例设计模式的基本写法,以Java代码为例

  • 饿汉式:
public class Singleton {
    private static final Singleton instance = new Singleton(); // 类加载时就被创建

    private Singleton() {
        // 私有构造方法,防止外部实例化
    }

    public static Singleton getInstance() {
        return instance;
    }
} 
  • 懒汉式 + 互斥锁:
public class Singleton {
    private static final Singleton instance;

    private Singleton() {
        // 私有构造方法,防止外部实例化
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance == new Singleton();
        }
        return instance;
    }
} 
  • 懒汉式 + 双重检查锁提高性能:
public class Singleton {
    private static final Singleton instance;

    private Singleton() {
        // 私有构造方法,防止外部实例化
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance == new Singleton();
                }
            }
        }
        return instance;
    }
} 

在Java中,关键字synchronized用于实现线程的同步。

首先,synchronized可以用来修饰方法,表示该方法在同一时间只能被一个线程访问。当一个线程访问该方法时,其他线程必须等待该线程执行完毕才能访问该方法。

其次,synchronized还可以用来修饰代码块。当多个线程需要访问共享资源时,可以使用synchronized来保证同一时间只有一个线程可以访问该资源。synchronized代码块使用一个对象作为锁,当一个线程进入synchronized代码块时,会尝试获取该对象的锁,如果锁被其他线程占用,则该线程被阻塞,直到锁被释放。

synchronized的作用是避免多个线程对共享资源的并发访问导致的数据不一致或者错误。通过使用synchronized,可以保证在同一时间只有一个线程对共享资源进行访问,从而保证了线程安全。

"类.class"是Java编程中的一种语法结构,用于获取某个类的Class对象。在Java中,每个类都对应一个Class对象,该对象包含了有关类的结构、字段、方法等信息,可以在程序运行时通过反射机制来访问和操作类的成员。

通过类名后面添加".class",可以获得该类的Class对象。例如,"String.class"返回String类的Class对象,"Integer.class"返回Integer类的Class对象。

使用Class对象可以进行一些操作,比如实例化对象、访问类的静态成员、获取类的父类和接口等。

请注意,类.class只能用于获取该类的Class对象,不能用于实例化这个类的对象。要实例化一个类的对象,可以使用Class对象中的newInstance()方法或者使用构造函数来创建对象。

总结一下,我们应当什么时候使用单例设计模式:

  1. 如果多个模块都需要共享某一种资源,例如一个全局的配置管理器来存储管理配置信息、管理数据库连接池信息等,可以使用单例设计模式。
  2. 如果创建对象本身就比较消耗资源,而且可能在整个程序中都不一定会使用,就可以使用单例模式中的懒加载;
  3. 有些场景中只需要一个实例就足以协调所有行为,创建多个实例没有必要甚至会导致不好的后果,例如管理应用程序中的缓存、管理线程池。

管理应用程序中的缓存只需要一个缓存实例的原因是为了保持数据的一致性和避免冲突。

当应用程序使用多个缓存实例时,可能会导致以下问题:

  1. 数据一致性:如果多个缓存实例各自独立管理数据,那么在不同实例中的数据可能会不一致。当更新或删除数据时,如果没有及时同步所有的缓存实例,可能导致数据的不一致性,从而引发潜在的问题。

  2. 资源浪费:每个缓存实例都需要占用内存和其他资源,如果使用多个缓存实例,会造成资源的浪费。而只使用一个缓存实例可以更有效地利用资源。

  3. 缓存冲突:多个缓存实例可能会导致相同的数据被同时缓存在不同的实例中,从而造成缓存冲突。如果多个实例同时读写相同的数据,可能会引发并发问题,影响应用程序的性能和正确性。

通过只使用一个缓存实例,可以确保数据的一致性,并最大程度地节省资源。可以使用单例模式来创建和管理缓存实例,确保应用程序中只存在一个缓存对象。这样可以简化缓存管理的操作,提高系统的可靠性和性能。

【设计模式专题之单例模式】1.小明的购物车

 CPP版本:

#include <iostream>
#include <vector>
#include <map>
 
using namespace std;
 
class ShoppingCartManager {
public:
    // 获取购物车实例
    static ShoppingCartManager& getInstance() {
        static ShoppingCartManager instance;
        return instance;
    }
 
    // 添加商品到购物车
    void addToCart(const string& itemName, int quantity) {
        if (cart.find(itemName) == cart.end()) {
            order.push_back(itemName);
        }
        cart[itemName] += quantity;
    }
 
    // 查看购物车
    void viewCart() const {
        for (const auto& itemName : order) {
            cout << itemName << " " << cart.at(itemName) << endl; 
            // 不能使用cart[itemName],因为处在一个const方法,不能有修改变量值的格式出现。
        }
    }

private:
    // 私有构造函数
    ShoppingCartManager() {}
 
    // 购物车存储商品和数量的映射
    map<string, int> cart;
    // 记录加入购物车的顺序
    vector<string> order;
};

int main() {
    string itemName;
    int quantity;
 
    while (cin >> itemName >> quantity) {
        // 获取购物车实例并添加商品
        ShoppingCartManager& cart = ShoppingCartManager::getInstance();
        cart.addToCart(itemName, quantity);
    }
 
    // 输出购物车内容
    const ShoppingCartManager& cart = ShoppingCartManager::getInstance();
    cart.viewCart();
 
    return 0;
}

在C++中,static关键字可以有多种作用

  1. 静态变量(Static Variables):在函数内使用static关键字,可以创建静态变量。静态变量在函数调用结束后仍然存在,并且在下一次调用函数时保持其值不变。这使得静态变量在需要记住上一次函数调用结果或在多次调用之间共享数据时非常有用。

  2. 静态成员变量(Static Member Variables):在类内部使用static关键字,可以创建静态成员变量。静态成员变量属于类本身而不是类的实例,因此在不创建类的对象时也可以访问和修改它们。静态成员变量在类的所有实例之间共享数据。

  3. 静态函数(Static Functions):在类内部使用static关键字,可以创建静态函数。静态函数不依赖于类的实例,因此可以直接通过类名调用,无需创建类的对象。静态函数主要用于处理和类本身相关的操作,而不是与类的实例数据交互。

  4. 静态类(Static Classes):在C++中,可以将类声明为static类。静态类的成员函数和成员变量都必须是静态的,而且无法创建静态类的对象。静态类主要用于实现一些全局可访问的、不需要创建对象的功能,类似于命名空间的作用。

总的来说,C++中的static关键字可以用于创建静态变量、静态成员变量、静态函数以及静态类,它们都具有特定的作用和用途。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入了解 JavaScript 混淆加密和环境检测

JavaScript混淆加密是一种通过修改代码结构和命名约定来增加代码的复杂性&#xff0c;使其难以被理解和逆向工程的技术。在这篇文章中&#xff0c;我们将深入探讨JS混淆加密的一些逻辑&#xff0c;并介绍如何通过环境检测来提高代码的安全性。我们将使用案例代码演示这些概念。…

微信小程序开发学习笔记《18》uni-app框架-网络请求与轮播图

微信小程序开发学习笔记《18》uni-app框架-网络请求 博主正在学习微信小程序开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。建议仔细阅读uni-app对应官方文档 一、下载网络请求包 这个包是以前黑马程序员老师写的一个包&#xff0c;跟着课程学习&#x…

LSTM 长短期记忆递归神经网络

1、神经网络简介 1.1 神经网络起源 人工神经网络&#xff08;Aritificial Neural Networks, ANN&#xff09;是一种仿生的网络结构&#xff0c;起源于对人类大脑的研究。人工神经网络&#xff08;Aritificial Neural Networks&#xff09;也常被简称为神经网络&#xff08;Ne…

考研复试指南

1. 记住&#xff0c;复试的本质不是考试&#xff0c;而是一场自我展示。 考研复试并非简单的知识考察&#xff0c;更是一场展示自我能力和潜力的机会。除了学科知识&#xff0c;考官更关注你的综合素质、学术兴趣和未来发展规划。因此&#xff0c;要保持自信&#xff0c;用更全…

重读 Java 设计模式: 探索经典之道与 Spring 框架的设计

写在开头 记得大学刚毕业那会儿&#xff0c;想学点东西&#xff0c;于是拿出了《Head First 设计模式》这本书&#xff0c;就开始了阅读&#xff0c;我曾对这些模式感到晦涩难懂。然而&#xff0c;随着工作岁月的增长&#xff0c;我逐渐领悟到设计模式的价值&#xff0c;尤其是…

使用 Haproxy 搭建Web群集

Haproxy是目前比较流行的一种群集调度工具&#xff0c;同类群集调度工具有很多&#xff0c;如LVS 和Nginx。相比较而言&#xff0c;LVS.牲能最好&#xff0e;但是搭建相对复杂:Nginx的upstream模块支持群集功能&#xff0e;但是对群集节点健康检查功能不强&#xff0c;性能没有…

jupyter 一键快捷启动方法研究

1.效果 首先打开dat 文件&#xff0c;同意赋予管理员 输入序号1 成功启动 2.Bat代码 %1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0 ::","","runas",1)(window.close)&&e…

【网站项目】123网上书城系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Matlab 多项式插值(曲线拟合)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 由于对曲线拟合有些兴趣,这里就找了一些资料从最基本的方法来看一下曲线拟合的效果: 二、实现代码 % **********

后端开发技术面试指南

工作10多年&#xff0c;每年都会帮组里面试一些新同学校招社招的都有&#xff0c;下面我就从一个面试官的视角来给大家拆解一下如何淡然应对后端开发技术面试。 1.一面多为电话面试 (1)问七问八 ①简历要注重内容&#xff0c;形式上不丑没有错别字即可。之前收到过一个工作5…

代码随想录算法训练营第七天

● 自己看到题目的第一想法 第454题.四数相加II 方法&#xff1a; 方法一&#xff1a; 暴力法 思路&#xff1a; 注意&#xff1a; 代码&#xff1a; class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<i…

SpringBlade CVE-2022-27360 export-user SQL 注入漏洞分析

漏洞描述 SpringBlade是一个基于Spring Cloud和Spring Boot的开发框架&#xff0c;旨在简化和加速微服务架构的开发过程。它提供了一系列开箱即用的功能和组件&#xff0c;帮助开发人员快速构建高效可靠的微服务应用。该产品/api/blade-user/export-user接口存在SQL注入。 漏…

探索Hadoop的三种运行模式:单机模式、伪分布式模式和完全分布式模式

目录 前言一、 单机模式二、 伪分布式模式三、 完全分布式模式&#xff08;重点&#xff09;3.1 准备工作3.2 配置集群3.2.1 配置core-site.xml 文件3.2.2 配置hdfs-site.xml 文件3.2.3 配置yarn-site.xml 文件3.2.4 配置mapred-site.xml 文件 3.3 启动集群3.3.1 配置workers3.…

神经网络系列---卷积

文章目录 卷积神经网络卷积转置卷积 卷积核和反卷积的三种实现方式卷积的次数计算 卷积神经网络 在神经网络的卷积层中&#xff0c;向下取整&#xff08;Floor&#xff09;是一种常用的策略&#xff0c;特别是在处理输出尺寸不是整数的情况时。当你计算出卷积层输出的尺寸&…

【 10X summary report】怎么看?详细解读笔记

报告内容 在开始正式的分析之前&#xff0c;需要查看在对齐和计数过程中生成的任何总结统计信息。下图是由Cell Ranger工具创建的10X总结报告&#xff0c;在从10X scRNA-seq实验生成计数矩阵时会生成。 The left half of the report describes sequencing and mapping statist…

李沐动手学习深度学习——3.1练习

字写的有点丑不要介意 由于公式推导烦的要死&#xff0c;所以手写形式&#xff0c;欢迎进行讨论&#xff0c;因为我也不知道对错

2024最新AI系统ChatGPT网站源码, AI绘画系统

一、前言说明 R5Ai创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持GP…

lua调用C++函数

第一步搭建lua的环境. win10 lua环境搭建-CSDN博客 我使用的环境是win10vs2015lua54 先来个最简单的lua调用C函数, 无参数无返回值的 第一步:定义C函数. int CTest(lua_State* L) // 返回值是固定的int类型,返回0表示没有返回参数,返回1表示有一个返回参数 {std::cout &l…

模型部署 - BevFusion - (1) - 思路总结

模型部署实践 - BevFusion 思路总结一、网络结构 - 总结1.1、代码1.2、网络流程图1.3、模块大致梳理 二、Onnx 的导出 -总体思路分析三、优化思路总结 学习 BevFusion 的部署&#xff0c;看了很多的资料&#xff0c;这篇博客进行总结和记录自己的实践 思路总结 对于一个模型我…

自学高效备考2025年AMC8数学竞赛:2000-2024年AMC8真题解析

今天继续来随机看五道AMC8的真题和解析&#xff0c;根据实践经验&#xff0c;对于想了解或者加AMC8美国数学竞赛的孩子来说&#xff0c;吃透AMC8历年真题是备考最科学、最有效的方法之一。下面的五道题目如果你能在8分钟内做对&#xff08;主要结果对&#xff0c;无需过程&…
最新文章