C++ 程序设计:单例+原型(手机原型机和量产机)

news/2024/4/20 16:01:04/文章来源:https://blog.csdn.net/weixin_42549534/article/details/131701775

1.简介

1.1单例模式

C++单例模式被广泛应用于需要全局唯一实例的场景。以下是一些常见的使用场景:

  1. 日志记录器
    在大多数应用程序中,需要一个全局的日志记录器来记录系统运行时的事件和错误。使用单例模式可以确保只有一个日志记录器实例,并能够在整个应用程序中共享和访问。

  2. 数据库连接池
    数据库连接是有限且昂贵的资源,为了避免频繁地创建和销毁连接,可以使用单例模式来管理数据库连接池。这样可以确保在应用程序中只有一个连接池实例,并且可以在需要时轻松获取数据库连接。

  3. 配置管理器
    配置管理器负责加载和管理应用程序的配置信息,例如数据库连接字符串、日志级别等。通过单例模式,可以确保只有一个配置管理器实例,并能够在整个应用程序中统一访问配置信息。

  4. 全局对象管理器
    在某些应用程序中,可能存在需要全局访问的对象,例如全局事件管理器、全局资源管理器等。使用单例模式可以确保这些全局对象只有一个实例,并能够在整个应用程序中方便地进行访问和使用。

  5. 线程池
    线程池用于管理和调度多个线程执行任务,通过单例模式,可以确保只有一个线程池实例,并能够在整个应用程序中灵活地进行任务分发和执行。

这些只是一些常见的使用场景,实际上,单例模式可以适用于任何需要一个全局唯一实例的情况。但是,需要注意的是,单例模式可能会带来全局共享状态的问题,因此在使用单例模式时需要仔细考虑其潜在的风险和副作用。同时,还要记住,在多线程环境中使用单例模式需要考虑线程安全性。

1.2 原型模式

      原型模式是一种通过复制现有对象来创建新对象的设计模式。它使用一个原型对象作为创建对象的样板,通过克隆原型对象来生成新的对象,而不是使用传统的实例化过程。
      原型模式的核心思想是使用已有对象作为原型,通过复制(克隆)这个原型来创建新的对象,而不是通过传统的实例化方式。这种方式允许我们在运行时动态地创建对象,并且可以避免耗费时间和资源去重新初始化对象。

1.3 比喻-手机原型机和量产机

原型模式和单例模式可以这样比喻我们要制作一款手机:

  1. 原型模式比喻为手机的制作过程中,我们先制作一个原型机,并通过复制原型机来制造更多的手机。原型机是一个已经设计好的模板,我们可以根据它来制造新的手机,而每个手机都可以独立使用和修改。这样,我们可以根据原型机的特性和功能来扩展和修改手机,从而得到多个不同的手机实例。

  2. 单例模式比喻为手机的制造过程中,我们只允许制造一台手机,这台手机成为该品牌的唯一代表。无论是在什么地方,我们都只能获得并使用这一台手机。这样做的好处是,我们可以保证这台手机的唯一性,避免资源浪费,并且方便全局访问。

2.单例的简单实现

class SysParaData : 
{
public:static SysParaData &instance(){static SysParaData self;return self;}private:SysParaData();~SysParaData();SysParaData(const SysParaData &self);const SysParaData &operator=(const SysParaData &self);
};

这里用单例模式定义了一个全局只有一个的数据参数类,用来存储全局的参数。

    在类中,instance()是一个公共的静态成员函数,用于返回SysParaData类的唯一实例。这个函数通过局部静态变量self来实现,在第一次调用instance()函数时创建实例。由于局部静态变量在函数退出后仍然存在,所以每次调用instance()函数都会返回同一个实例。

   同时,构造函数、析构函数、拷贝构造函数和赋值运算符被声明为私有,这意味着不能从类的外部直接实例化、销毁、复制或赋值SysParaData对象。这样可以确保只有instance()函数可以创建和访问SysParaData类的唯一实例。

    单例模式的优点之一是可以提供全局唯一的对象访问点,方便在程序中的任何地方使用该对象。通过调用SysParaData::instance()函数,可以获得对SysParaData类的唯一实例的引用。

注意:这里没有进行多线程安全的处理。如果在多线程环境中使用该单例模式,可能需要额外的线程同步措施,以确保线程安全。例如使用互斥锁或其他线程同步机制来保护实例的创建和访问过程。

3.原型模式的简单实现

// 原型类
class SysParaModifyDataBase
{
public:virtual SysParaModifyDataBase *Clone() = 0;
};//
class SysParaModifyData: public SysParaModifyDataBase
{
public:SysParaModifyData()virtual Prototype *Clone(){return new SysParaModifyData(*this);}int data = 1;
};SysParaModifyDataBase *dataSource = new SysParaModifyData();
SysParaModifyDataBase *dataModify = dataSource ->Clone();

4.原型模式和单例模式的结合

class SysParaData :
{
private:static SysParaData *instance; public:/* 禁止拷贝构造函数 禁止拷贝赋值运算符的另一种写法 与上面单例代码设为私有效果一样 */SysParaData (const SysParaData &) = delete;SysParaData & operator=(const SysParaData &) = delete;/* 单例实例的另一种写法 */static SysParaData *getInstance() {if (instance == nullptr) {instance = new SysParaData ();}return instance;}void setName(const std::string& newName) {name = newName;}std::string getName() const {return name;}SysParaData *clone() const {SysParaData *cloneInstance = new SysParaData ();cloneInstance->setName(this->name);return cloneInstance;}
};

如果使用clone()方法克隆一个SysParaData对象,并使用该克隆对象调用setName()修改名称,那么原始的单例对象将不受影响,它们是相互独立的。因此,克隆对象和原始单例对象不再是同一个单例。

单例模式的规则是一个类只能有一个实例,并且通过getInstance()方法获取单例实例。在这个例子中,我们使用静态变量instance来存储唯一的单例实例,而且通过禁止拷贝构造函数和拷贝赋值运算符的使用来确保只有一个实例。克隆方法clone()是为了使用已有的单例对象来创建新的对象实例。

     被克隆之后的对象如果不使用clone()方法创建,而是直接使用单例对象的指针进行赋值或传递,那么它们仍然是指向同一个单例的指针。

例如:

SysParaData *singleton = SysParaData::getInstance();
SysParaData *cloneInstance = singleton->clone();  // 克隆单例对象SysParaData *directAssignment = singleton;        // 直接赋值
SysParaData *functionParameter = cloneInstance;   // 作为函数参数传递// 修改单例对象的名称
singleton->setName("Singleton");// 输出对象的名称
std::cout << "Singleton Name: " << singleton->getName() << std::endl;
std::cout << "Direct Assignment Name: " << directAssignment->getName() << std::endl;
std::cout << "Function Parameter Name: " << functionParameter->getName() << std::endl;

输出结果将会是:

Singleton Name: Singleton
Direct Assignment Name: Singleton
Function Parameter Name: Cloned Instance

可以看到,直接赋值或作为函数参数传递的对象指针仍然指向同一个单例对象,因此它们的名称相同。只有通过clone()方法创建的对象是一个独立的克隆实例,它们和原始单例对象是不同的。

因此,被克隆之后的对象,如果不使用clone()方法创建,而是直接使用单例对象的指针进行赋值或传递,仍然是指向同一个单例实例,因此仍然是单例。

5.总结

    当原型模式与单例模式结合在一起时,可以实现一个可以克隆的单例。

     在传统的单例模式中,类只能有唯一的一个实例,并且使用静态方法获取该实例。而在原型模式中,可以通过复制原型对象来创建新的对象实例。

    当将这两种模式结合在一起时,通过克隆原型对象,可以创建多个具有相同属性和行为的实例,同时保持单例的特性,即每次克隆都得到同一个实例。

    这种结合模式的应用场景是当希望在单例基础上创建新的对象实例,这些新实例保持与原始实例相同的初始状态,并且这些实例之间相互独立。

    使用这种结合模式,可以方便地创建多个独立且具有相同初始状态的对象,同时避免了在使用时传递参数的麻烦。它提供了更大的灵活性和可扩展性,同时仍然保持了单例的特性。

注意:此结合模式的实现需要对原型对象进行深度拷贝,以确保每个克隆对象是独立的。否则,如果使用浅拷贝,所有克隆对象将共享同一个状态,这不符合原型模式的预期。

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

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

相关文章

第G1周:生成对抗网络(GAN)入门

目录 一、课题背景和开发环境二、理论基础1.生成器2. 判别器3. 基本原理 三、前期准备工作1. 定义超参数2.下载数据3. 配置数据 四、定义模型1. 定义鉴别器2. 定义生成器 五、训练模型1. 创建实例2. 训练模型3. 保存模型 &#x1f368; 本文为&#x1f517;365天深度学习训练营…

prometheus调整默认数据存储时间

调整kubernetes部署的prometheus数据存储时间 由于prometheus是用kuberentes部署的&#xff0c;没办法像传统部署方式那种直接在启动参数增加存储时间的参数。需要在configmap里或者在deployment里添加&#xff0c;我这里使用的方式是在deployement里添加调整存储时间的参数。…

React native 已有项目升级兼容web

基础 概念 | webpack 中文文档 | webpack 中文文档 | webpack 中文网 深入理解Webpack及Babel的使用 - 掘金 Introduction to React Native for Web // React Native for Web Webpack 是一个现代的 JavaScript 应用程序的静态模块打包工具&#xff0c;它将应用程序所依赖的各…

Star History 月度开源精选|2023 年 6 月

上一期 Star History 月度精选是写给市场、运营人员的&#xff0c;而这一期回归到 DevTools 类别&#xff0c;我们六月发现了好一些开发者可以用的不错工具&#xff01; AI Getting Started 还记得 Supabase “Build in a weekend” 的广告词吗&#xff01;AI Getting Started…

AIGC文生图:使用ControlNet 控制 Stable Diffusion

1 ControlNet介绍 1.1 ControlNet是什么&#xff1f; ControlNet是斯坦福大学研究人员开发的Stable Diffusion的扩展&#xff0c;使创作者能够轻松地控制AI图像和视频中的对象。它将根据边缘检测、草图处理或人体姿势等各种条件来控制图像生成。 论坛地址&#xff1a;Adding…

Docker安装Rabbitmq超详细教程

&#x1f680; Docker安装Rabbitmq保姆级教程 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1…

Java 装箱拆箱原理 包装类型缓存池

JAVA中的基本数据类型 byteshortintlongfloatdoublebooleanchar 为了让上述基本数据类型可以转为对象&#xff0c;Java在1.5推出了一系列包装类&#xff0c;基本类和包装类互相转换的过程&#xff0c;称为装箱和拆箱 缓存池 缓存池也叫常量池。它是事先存储一些常量数据用以…

数据结构——各种常见算法的实现方法和思路

文章目录 常见的排序算法类型复杂度和稳定性 1.冒泡排序2.直接插入排序3.希尔排序4.简单选择排序方法1&#xff1a;双向遍历选择排序方法2&#xff1a;单向遍历选择排序 5.归并排序方法1&#xff1a;递归方法2&#xff1a;非递归 6.快速排序方法1&#xff1a;随机取keyi方法2&a…

JMeter自定义日志与日志分析

1 JMeter日志概览 JMeter与Java程序一样&#xff0c;会记录事件日志&#xff0c;日志文件保存在bin目录中&#xff0c;名称为jmeter.log。当然&#xff0c;我们也可以在面板中直接察看日志&#xff0c;点击右上角黄色标志物可以打开日志面板&#xff0c;再次点击收起。 可见&…

PostgreSQL MVCC的弊端优化方案

我们之前的博客文章“我们最讨厌的 PostgreSQL 部分”讨论了大家最喜欢的 DBMS 多版本并发控制 (MVCC) 实现所带来的问题。其中包括版本复制、表膨胀、索引维护和真空管理。本文将探讨针对每个问题优化 PostgreSQL 的方法。 尽管 PostgreSQL 的 MVCC 实现是 Oracle 和 MySQL 等…

layui会议OA项目数据表格新增改查

文章目录 前言一、后台代码编写1.1 数据表优化1.2 R工具类1.3 UserDao新增改查1.4 Servlet的编写 二、前台页面的编写2.1 userManege.jsp2.2 userManage.js2.3 新增、修改用户共用jsp2.4add、edit的js 三、演示3.1 查询3.2 新增3.3 修改3.4 删除 前言 在上篇博客我们实现了左侧…

【数据结构】二叉树——链式结构

目录 一、前置声明 二、二叉树的遍历 2.1 前序、中序以及后序遍历 2.2 层序遍历 三、节点个数以及高度 3.1 节点个数 3.2 叶子节点个数 3.3 第k层节点个数 3.4 二叉树的高度/深度 3.5 查找值为x的节点 四、二叉树的创建和销毁 4.1 构建二叉树 4.2 二叉树销毁 4.3 …

Javaweb的三大组件:servlet、filter、listener

1.前言 Servlet翻译过来是小服务程序&#xff0c;所以呢&#xff0c;在javaweb中Servlet是用来处理客户端请求的动态资源&#xff0c;一般表示小程序&#xff0c;在实际开发javaweb的过程中使用的比较多一些&#xff0c;通常的使用方法是根据具体的业务需求来继承HttpServlet&a…

Rdkit|分子3D构象生成与优化

github; 地址 文章目录 Rdkit|分子3D构象生成与优化构象生成算法概述基于距离&#xff08;distance-based&#xff09;代码示例 距离几何算法生成3D结构距离几何ETKDG生成3D构象距离几何ETKDG生成多构象将Conformer类转为Mol类手动对齐 距离几何ETKDGMMFF生成3D构象距离几何ETK…

Node.js 版本管理工具 n 使用指南

Node.js 版本更新很快&#xff0c;目前 node v20.x 已经发布&#xff0c;我们在使用时避免不了会需要切换不同的 Node.js 的版本来使用不同版本的特性。 所以就出现了像 windows 上的 nvm&#xff0c;MacOS 上的 n 工具&#xff0c;本文就介绍一下如何使用 n 管理 Node.js 的版…

InsCode Stable Diffusion使用教程【InsCode Stable Diffusion美图活动一期】

记录一下如何使用 InsCode Stable Diffusion 进行 AI 绘图以及使用感受。 一、背景介绍 目前市面上比较权威&#xff0c;并能用于工作中的 AI 绘画软件其实就两款。一个叫 Midjourney&#xff08;简称 MJ&#xff09;&#xff0c;另一个叫 Stable Diffusion&#xff08;简称 …

FPGA——按键控制led灯

文章目录 一、实验环境二、实验任务三、系统设计四、实验过程4.1 编写verilog代码4.2 引脚配置 五、仿真5.1 仿真代码5.2 仿真结果 六、实验结果七、总结 一、实验环境 quartus 18.1 modelsim vscode Cyclone IV开发板 二、实验任务 使用开发板上的四个按键控制四个LED灯。按…

【微信小程序创作之路】- 小程序窗口整体配置(导航栏、标题)

【微信小程序创作之路】- 小程序窗口导航栏配置 第五章 微信小程序窗口导航栏配置 文章目录 【微信小程序创作之路】- 小程序窗口导航栏配置前言一、入口文件的配置二、页面配置三、全局默认窗口配置1.navigationBarTitleText&#xff1a;导航栏标题文字2.navigationBarBackgr…

​​Layui之用户管理实例(对数据的增删改查)

目录 ​编辑一、R工具介绍&#xff08;&#xff09; ​编辑二、数据表的增删改查 ​编辑2.1我们先得从查询数据库的语句入手 2.2优化dao类 2.4UserAction类 2.5前台的页面实现增删改查操作 2.6 userManage页面JS 2.7user新增、修改iframe层js 前言 上一篇我分享了…

SpringCloudAlibaba:消息驱动之RocketMQ学习

目录 一、MQ简介 &#xff08;一&#xff09;什么是MQ &#xff08;二&#xff09;MQ的应用场景 1、异步解耦 2、流量削峰 &#xff08;三&#xff09;常见的MQ产品 二、RocketMQ入门 &#xff08;一&#xff09;RocketMQ安装部署 1、环境要求 2、下载RocketMQ 3、安…