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

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.mzph.cn/news/4775.shtml

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

相关文章

韩老师多目标优化:多目标粒子群算法

一. 内容简介 韩老师多目标优化&#xff1a;多目标粒子群算法 视频: 【2022.2.5韩老师十七课时&#xff08;中&#xff09;多目标优化&#xff1a;多目标粒子群算法】 https://www.bilibili.com/video/BV1eS4y157Xg/?share_sourcecopy_web&vd_source7b377d4a833a67013df5…

libevent:windows环境配置+QT使用

目录 libevent是什么 编译 QT使用 测试代码 libevent是什么 Fast portable non-blocking network programming with Libevent http://www.wangafu.net/~nickm/libevent-book/TOC.html 这篇文档讲的很清楚&#xff0c;尤其是Chapter 1: A tiny introduction to asynchro…

大数据面试基础回答

以下是Hive大数据领域的一些常见问题&#xff1a; 数据倾斜&#xff1a;在Hive中&#xff0c;数据倾斜是一个常见的问题&#xff0c;它会导致查询结果不准确或查询过程异常。为了解决数据倾斜问题&#xff0c;可以尝试以下方法&#xff1a; 使用更高效的数据倾斜处理工具&…

cURL error 1014: SSL verify failed 报错

报错 [ERROR] cURL error 1014: SSL verify failed (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://mgobe.tencentcloudapi.com/[247] in /www/wwwroot/*.net/vendor/ [ERROR] #0 /www/wwwroot/tencentgame.net/vendor/tencentcloud/tencentcloud-sdk…

matlab入门

命名规则&#xff1a; clc&#xff1a;清除命令行的所有命令 clear all&#xff1a;清除所有工作区的内容 注释&#xff1a;两个% 空格 %% matlab的数据类型 1、数字 3 3 * 5 3 / 5 3 5 3 - 52、字符与字符串 s a %% 求s的ascill码 abs(s) char(97) num2str(65) str I…

代码随想录第48天|198.打家劫舍, 213.打家劫舍II ,337.打家劫舍III

LeetCode198.打家劫舍 题目链接&#xff1a;198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; class Solution { public:int rob(vector<int>& nums) {if(nums.size() 0) return 0;if(nums.size() 1) return nums[0];vector<int> …

家政小程序开发-H5+小程序

移动互联网的发展&#xff0c;微信小程序逐渐成为商家拓展线上业务的重要手段。家政服务作为日常生活中不可或缺的一部分&#xff0c;也开始尝试通过小程序来提高服务质量和效率。 下面是一篇关于家政小程序开发的H5小程序的文章&#xff0c;希望对您有所帮助。 家政服…

Redis进阶底层原理- 缓冲区

Redis中使用了很多缓冲区&#xff0c;在redis各个环节起到了非常核心的作用。下面来一一介绍一下&#xff1a; 输入输出缓冲区&#xff08;客户端缓冲区&#xff09; Redis中的输入输出缓冲区是为了平衡客户端发送命令和服务端处理命令的速度差异&#xff0c;如果客户端发送指…

一本通1910:【00NOIP普及组】计算器的改良题解

今天是编程集训的第二天&#xff0c;也是我来到CSDN整整1年。感谢所有阅读过我的文章的人&#xff0c;谢谢。 今天的比赛难度略低于昨天&#xff0c;但这道题也卡了我好久。 进入正题 题目&#xff1a; 题目描述&#xff1a; NCL是一家专门从事计算器改良与升级的实验室&a…

手把手带你实现ChatGLM2-6B的P-Tuning微调

参考文献&#xff1a;chatglm2ptuning 注意问题1&#xff1a;AttributeError: ‘Seq2SeqTrainer’ object has no attribute is_deepspeed_enabl torch.distributed.elastic.multiprocessing.errors.ChildFailedError: 可能是版本太高&#xff0c;可以参考chatglm2的环境

mysql笔记

目录 1、root用户密码忘记 2、SQL的分类 2.1、DQL数据查询语言 前言 2.1.1、设置别名 2.1.2、去除重复行 2.1.3、空值参与运算 2.1.4、着重号 2.1.5、显示表结构 2.1.6、算数运算符 2.1.7、比较运算符 2.1.8、逻辑运算符 2.1.9、位运算符 2.1.10、 模糊查询 2.1.…

深信服社招linux岗位面试题汇总

1、结构体变量是否能直接比较&#xff1f; A&#xff1a; 2、static关键字的用法&#xff1f;static修饰的变量和普通局部变量有什么区别&#xff1f;各自存放在哪里&#xff1f; 3、函数参数是怎么传递的&#xff08;网上也有小伙伴分享这个问题&#xff09; 我回答了调用…

基于Java+SpringBoot+Vue前后端分离校园管理系统详细设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

sqli-labs 堆叠注入 解析

打开网页首先判断闭合类型 说明为双引号闭合 我们可以使用单引号将其报错 先尝试判断回显位 可以看见输出回显位为2&#xff0c;3 尝试暴库爆表 这时候进行尝试堆叠注入&#xff0c;创造一张新表 ?id-1 union select 1,database(),group_concat(table_name) from informatio…

分布式应用之zookeeper集群+消息队列Kafka

一、zookeeper集群的相关知识 1.zookeeper的概念 ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Google的Chubby一个开源的实现&#xff0c;是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件&#xff0c;提供的功能…

[刷机] 9008 刷机救砖笔记

前几日, 我拿着手里的 OnePlus 8T 作死, 成功的把它作成了砖, 系统分区嗝屁, recovery 和 bootloader 分区也都嗝屁, 换言之, 只能使用 9008 进行刷机了… 什么是 9008 深刷 按照网上的介绍, 9008 是骁龙系列处理器的手机专有的, 用于为手机硬件下载数据的模式. 只要手机还能…

一级分类全覆盖!安全狗入选《嘶吼2023网络安全产业图谱》

7月10日&#xff0c;嘶吼安全产业研究院联合国家网络安全产业园区&#xff08;通州园&#xff09;正式发布《嘶吼2023网络安全产业图谱》。作为国内云原生安全领导厂商&#xff0c;安全狗入选图谱中的多个细分领域。 据悉&#xff0c;本次《嘶吼2023网络安全产业图谱》采用了市…

JavaScript——基础知识及使用

初识 JavaScript JavaScript (简称 JS) 是世界上最流行的编程语言之一.一个脚本语言, 通过解释器运行.主要在客户端(浏览器)上运行, 现在也可以基于 node.js 在服务器端运行. JavaScript 的能做的事情: 网页开发(更复杂的特效和用户交互)网页游戏开发服务器开发(node.js)桌…

ReLU激活函数

ReLU&#xff08;Rectified Linear Unit&#xff09;激活函数是一种常用的非线性激活函数&#xff0c;其原理是在输入小于等于零时输出为零&#xff0c;在输入大于零时输出等于输入值。ReLU激活函数的作用是引入非线性变换&#xff0c;使得神经网络可以学习更复杂的模式和特征。…

新手学c#常用到的语法记录

C# 是一种面向对象的编程语言。在面向对象的程序设计方法中&#xff0c;程序由各种相互交互的对象组成。相同种类的对象通常具有相同的类型&#xff0c;或者说&#xff0c;是在相同的 class 中。 例如&#xff0c;以 Rectangle&#xff08;矩形&#xff09;对象为例。它具有 l…