C++设计模式|创建型 1.单例模式

1.什么是单例模式?

单例模式的的核⼼思想在创建类对象的时候保证⼀个类只有⼀个实例,并提供⼀个全局访问点来访问这个实例。

  • 只有⼀个实例的意思是,在整个应⽤程序中,只存在该类的⼀个实例对象,⽽不是创建多个相同类型的对象。
  • 全局访问点的意思是,为了让其他类能够获取到这个唯⼀实例,该类提供了⼀个全局访问点(通常是⼀个静态⽅法),通过这个⽅法就能获得实例。

 2.单例设计模式的优点

  • 全局控制:保证只有⼀个实例,这样就可以严格的控制客户怎样访问它以及何时访问它,简单的说就是对唯⼀实例的受控访问。
  • 节省资源:也正是因为只有⼀个实例存在,就避免多次创建了相同的对象,从⽽节省了系统资源,⽽且多个模块还可以通过单例实例共享数据。
  • 懒加载:单例模式可以实现懒加载,只有在需要时才进⾏实例化,能够提⾼程序的性能。

3. 单例设计模式的要求

  • 私有的构造函数:C++类的私有权限使得构造函数只能在类内部被访问,防⽌外部代码直接创建类的实例。
  • 私有的静态实例变量:C++中类的静态成员(变量或函数)归类所有,是类的所有实例所共享的。将实例变量设为静态,表明这个类的实例变量唯一。设为私有,辨明该实例在类外必须通过公有的接口来获得。
  • 公有的静态方法getInstance():这个就是上面所述的获取唯一实例的借口。静态也使其具有唯一的性质。

 4.单例模式的实现

按照实例创建的时机,单例模式有着多种实现方式,包括懒汉式、饿汉式等。

饿汉式:在类加载时就已经完成了实例的创建,不管后面创建的实例有没有使用,先创建再说,所以叫做 “饿汉”。

懒汉式:只有在请求实例时才会创建,如果在首次请求时还没有创建,就创建一个新的实例,如果已经创建,就返回已有的实例,意思就是需要使用了再创建,所以称为“懒汉”。

多线程环境下,由于饿汉式在程序启动阶段就完成了实例的初始化,因此不存在多个线程同时尝试初始化实例的问题,但是懒汉式中多个线程同时访问 getInstance() 方法并且在同一时刻检测到实例没有被创建,就可能会同时创建实例,从而导致多个实例被创建,这种情况下我们可以采用一些同步机制,例如使用互斥锁来确保在任何时刻只有一个线程能够执行实例的创建。

5.C++代码实战

小明的购物车icon-default.png?t=N7T8https://kamacoder.com/problempage.php?pid=1074

题目描述:

小明去了一家大型商场,拿到了一个购物车,并开始购物。请你设计一个购物车管理器,记录商品添加到购物车的信息(商品名称和购买数量),并在购买结束后打印出商品清单。(在整个购物过程中,小明只有一个购物车实例存在)。

输入描述

输入包含若干行,每行包含两部分信息,分别是商品名称和购买数量。商品名称和购买数量之间用空格隔开。

输出描述

输出包含小明购物车中的所有商品及其购买数量。每行输出一种商品的信息,格式为 "商品名称 购买数量"。

输入示例

Apple 3
Banana 2
Orange 5

输出示例 

Apple 3
Banana 2
Orange 5

提示信息 

本道题目请使用单例设计模式: 

使用私有静态变量来保存购物车实例

使用私有构造函数防止外部直接实例化

思路分析:

题目要求使用单例模式设计一个购物车管理器,那么这个管理器的类就是需要进行单例设置的类。包括私有的构造函数、私有的静态实例以及公有的实例获取方法接口。

代码实现:

#include<iostream>
#include<map>
#include<string>
using namespace std;

class ShoppingManager{
private:
    //私有的构造函数防止类外实例化
    ShoppingManager(){}
    
    //使用map作为购物车存放商品名级商品数量
    map<string,int> cart;
    
public:
    //公有的静态接口函数,获取实例
    static ShoppingManager&  getInstance()
    {
        //静态实例。由于构造函数私有,所以该实例也算是必须类内调用构造函数才能得到。带有私有的含义
        static ShoppingManager instance;  
        return instance;
    }
    
    //析构函数
    ~ShoppingManager(){}
    
    //将商品添加到购物车。const保证数据不会误改,引用&避免拷贝
    void addGoods(const string& name,const int& num)
    {
        cart[name] += num;  //+=保证同名商品数量叠加而不是重写覆盖
    }
    
    //查看购物车.  注意const的作用
    void viewCart() const 
    {
        //正常访问
        // for(auto it = cart.begin(); it!= cart.end();++it)  {
        //     cout<<it->first<<" "<<it->second<<endl;
        // }
        
        //避免迭代器修改的访问。注意,迭代器类似指针,所以访问map的内容用->
        // for(map<string,int>::const_iterator it = cart.cbegin(); it!=cart.cend();++it)
        // {
        //     cout<<it->first<<" "<<it->second<<endl;
        // }
        
        
        //如果是范围for语句,则得到的是map的每一个成员,属于pair类型,用.点来访问内容
        for( const auto  & member: cart)
        {
            cout<<member.first<<" "<<member.second<<endl;
        }
    }
    
};

int main()
{
    string name;
    int num;
    //按行读数据,可以使用while循环配合cin
    while(cin>>name>>num)
    {
        //由于单例模式的构造函数私有,无法直接点用构造函数实例化,所以无法通过对象调用getInstance
        //因此,可以使用类名::getInstance()的方式来获取单例
        ShoppingManager & myCart = ShoppingManager::getInstance();
        myCart.addGoods(name,num);
    }
    // 输出购物车内容。
    const ShoppingManager& myCart = ShoppingManager::getInstance();
    myCart.viewCart();
    return 0;
}

    由于实例是静态的,所以它的生存周期会在程序运行结束才销毁,且唯一,存放在全局区,因此即使第一次创建实例时是在while循环里面,第二次再使用getInstance获取它时,仍能获取到这个唯一的实例,其数据为最近一次更改后的数据。

6.应用场景

  • 资源共享

        多个模块共享某个资源的时候,可以使用单例模式,比如说应用程序需要一个全局的配置管理器来存储和管理配置信息、亦或是使用单例模式管理数据库连接池。

  • 只有一个实例

        当系统中某个类只需要一个实例来协调行为的时候,可以考虑使用单例模式, 比如说管理应用程序中的缓存,确保只有一个缓存实例,避免重复的缓存创建和管理,或者使用单例模式来创建和管理线程池。

  • 懒加载

        如果对象创建本身就比较消耗资源,而且可能在整个程序中都不一定会使用,可以使用单例模式实现懒加载

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

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

相关文章

WPS二次开发系列:Gradle版本、AGP插件与Java版本的对应关系

背景 最近有体验SDK的同学反馈接入SDK出现报错&#xff0c;最终定位到原因为接入的宿主app项目的gradle版本过低导致&#xff0c;SDK兼容支持了android11的特性&#xff0c;需要对应的gradle插件为支持android11的版本。 现象 解决方案 将gradle版本升级至支持android11的插件版…

openGauss_5.0.1 企业版安装及问题记录(CentOS系统):主备模式服务器安装

目录 &#x1f4da;第一章 官方地址&#x1f4d7;安装包下载地址&#x1f4d7;文档指南 &#x1f4da;第二章 安装&#x1f4d7;准备工作&#x1f4d7;开始安装&#x1f4d5;创建XML配置文件&#x1f4d5;初始化安装环境&#x1f4d5;执行安装&#x1f4d5;验证 &#x1f4da;第…

volta(轻松切换管理Node.js版本)

Node.js版本管理 Volta提供了一个简单直观的命令行界面&#xff0c;可以轻松地安装、卸载、更新和切换Node.js版本。 Volta 既可以全局使用&#xff0c;也可以在项目级别使用&#xff0c;可以为每个项目单独设置node版本&#xff0c;nvm不行。 下载安装Volta 参考&#xff1a; …

vue3 依赖-组件tablepage-vue3说明文档,列表页快速开发,使用思路及范例(Ⅲ)列表项及分页器配置及props配置

vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例&#xff08;Ⅰ&#xff09;配置项文档 vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例&#xff08;Ⅱ&#xff09;搜索及数据获取配…

基于SpringBoot的冬奥会科普平台

基于SpringBoot的冬奥会科普平台系统设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发…

pip install opencv-python出现ModuleNotFoundError: No module named ‘skbuild‘错误解决方案

问题描述 File “”, line 1, in File “/tmp/pip-build-o148qsmj/opencv-python/setup.py”, line 10, in from skbuild import cmaker, setup ModuleNotFoundError: No module named ‘skbuild’ Command “python setup.py egg_info” failed with error code 1 in /tmp…

Java入门-数组

数组 什么是数组 数组( array )是一种最简单的复合数据类型&#xff0c;它是有序数据的集合&#xff0c;数组中的每个元素具有相同的数据类型&#xff0c;可以用一个统一的数组名和不同的下标来确定数组中唯一的元素。 数组的内存结构是分配一系列内存大小相等的连续空间。 …

Vue 引入config.js后别的js访问不到window对象下的属性

Vue项目里,我们项目配置的请求服务器地址都是在public里config.js里,如下例: 然后在index.html里引入config.js,如下图: 这里要注意的是,script的src要写上<%= BASE_URL %>,代码如下: <!DOCTYPE html> <html><head><meta charset="…

SNRO 编号范围对象管控,唯一ID

事务代码:SNRO 代码引用: DATA: MAXTID TYPE I,NEWNO TYPE CHAR8. CALL FUNCTION NUMBER_RANGE_ENQUEUE EXPORTING OBJECT ZQC57 EXCEPTIONS FOREIGN_LOCK 1 OBJECT_NOT_FOUND 2 SYSTEM_FAILURE 3 OTHERS …

Python3.7编程之病毒

基础篇 什么是病毒 病毒&#xff0c;指的是一些通过非法手段获取系统的一些权限&#xff0c;然后进行破坏或者盗取。 病毒分为两类&#xff1a; 1、破坏型 这类病毒往往会将系统弄的乱七八糟&#xff0c;比如把你的U盘删光&#xff0c;把你的系统背景调成黑客图片&#xff0c…

NoETL 公开课预告|下周二,第三代指标平台即将展露真容

100% 统一指标口径、100% 自动化指标开发、100% 灵活指标分析、强大的指标定义能力和查询加速性能、“管、研、用”一体、做“轻”数仓…… 很多小伙伴都非常好奇 buff 叠满的第三代指标平台 Aloudata CAN 到底长什么样。接下来我们安排了 7 期开箱直播&#xff0c;结合企业业…

Flutter学习13 - Widget

1、Flutter中常用 Widget 2、StatelessWidget 和 StateFulWidget Flutter 中的 widget 有很多&#xff0c;但主要分两种&#xff1a; StatelessWidget无状态的 widget如果一个 widget 是最终的或不可变的&#xff0c;那么它就是无状态的StatefulWidget有状态的 widget如果一个…

腾讯云向量数据库-RAG介绍

1.说明 RAG结合LLM(通用大预言模型)构件基于私有文档、专业领域知识、实时信息的charbot。 2.RAG的主要步骤 知识切片成chunk向量化chunk入库query检索知识chunk构件prompts调用llm生成回答 3.优势 快速构件demo快速理解rag社区支持 4.痛点 投入大效果差调优难 5.RAG应…

MURF1640CT-ASEMI快恢复二极管MURF1640CT

编辑&#xff1a;ll MURF1640CT-ASEMI快恢复二极管MURF1640CT 型号&#xff1a;MURF1640CT 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220F 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;16A 最大循环峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;4…

【Java】JDK1.8 HashMap源码,put源码详细讲解

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 在Java中&#xff0c;HashMap结构是被经常使用的&#xff0c;在面试当中也是经常会被问到的。这篇文章我给大家分享一下我对于HashMap结构源码的理解。 HashMap的存储与一般的数组不同&#xff0c;HashMap的每一个元素存…

SQLite从出生到现在(发布历史记录)(二十二)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;从 SQLite 3.5.9 迁移到 3.6.0&#xff08;二十一&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 引言&#xff1a; SQLite拥有别人无法比拟的装机量&#xff0c;究竟什么成就了SQLite呢&#xff0c;本…

WPS制作表格热图

最近看到一篇文献使用了表格热图&#xff0c;于是想着用wps制作一个类似的。表格热图可以使表格中的数字大小变得更加直观。 参考文献原文&#xff1a;Miller, O.L., Helman, D., Tal Svoray, Morin, E., Bonfil, D.J., 2019. Explicit wheat production model adjusted for s…

2024/4/2—力扣—栈的最小值

代码实现&#xff1a; typedef struct node {int val;struct node *next; } Node;typedef struct {struct node *top;int min; } MinStack;/** initialize your data structure here. */MinStack* minStackCreate() {MinStack *obj malloc(sizeof(*obj));obj->top NULL;ob…

Failure Unable to retrieve image details-解决Portainer与Docker v26不兼容问题

文章目录 前言解决过程解决方法一解决方法二 前言 今天登上服务器习惯性的升级了yum软件包&#xff0c;结果这一更新后导致Portainer不能正常使用&#xff0c;后续进行成功解决&#xff0c;简单记录一下 解决过程 事故过程模拟 当时顺手升级下docker版本(V26.0.1) 结果Porta…

Golang 状态机设计模式

本文介绍了Golang状态机模式的一个实现示例&#xff0c;通过该模式&#xff0c;可以解耦调用链&#xff0c;有助于实现测试友好的代码&#xff0c;提高代码质量。原文: Go State Machine Patterns 导言 在我们开发的许多项目中&#xff0c;都需要依赖某种运行状态从而实现连续操…