news 2026/5/21 14:00:00

原型模式-创建型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
原型模式-创建型

一、原型模式

1.1、定义

原型实例指定创建对象的种类,并通过拷贝这些原型,创建新的对象。即克隆,细胞分裂等。

1.2、核心思想

通过复制现有对象(原型)来创建新对象,而不是通过new新建实例

1.3、为什么需要原型模式

问题场景

创建角色,以孙悟空为例

// 装备类classEquipment{private:std::string name;intpower;public:Equipment(std::string name,intpower):name(name),power(power){}Equipment*clone()const{returnnewEquipment(name,power);}std::stringgetName()const{returnname;}intgetPower()const{returnpower;}voiddisplay()const{std::cout<<" "<<name<<" (威力:"<<power<<")"<<std::endl;}};
classSunWuKong{private:std::string name;inthealth;intattack;std::vector<std::string>skills;std::vector<Equipment*>equipment;public:SunWuKong(std::string name,inthealth,intattack):name(name),health(health),attack(attack){// 初始化技能skills.push_back("七十二变");skills.push_back("筋斗云");skills.push_back("火眼金睛");skills.push_back("法天象地");skills.push_back("身外身");// 初始化装备equipment.push_back(newEquipment("金箍棒",1000));equipment.push_back(newEquipment("锁子黄金甲",500));equipment.push_back(newEquipment("凤翅紫静",300));equipment.push_back(newEquipment("藕丝步云履",200));}// 复制构造函数SunWuKong(constSunWuKong&other):name(other.name),health(other.health),attack(other.attack),skills(other.skills),equipment(other.equipment){}// 拷贝赋值运算符SunWuKong&operator=(constSunWuKong&other){if(this!=&other){name=other.name;health=other.health;attack=other.attack;skills=other.skills;equipment=other.equipment;}return*this;}~SunWuKong(){for(auto&eq:equipment){deleteeq;}}};// 创建分身voidcreateCloneMonkey(){// 创建本体SunWuKong*original=newSunWuKong("齐天大圣",1000,100);// 吹毛化兵,创建分身vector<SunWuKong*>clones;for(inti=0;i<100000;++i){std::count<<"创建第 "<<i<<" 个分身\n";SunWuKong*clone=newSunWuKong(*original);clones.push_back(clone);}deleteoriginal;// 删除分身for(auto&clone:clones){deleteclone;}}

问题点:

  1. 性能上:每次创建分身时,都需要初始化技能和装备,效率低下
  2. 灵活性差,如果修改了本体,分身不会自动进行更新
  3. 浅拷贝问题,容易导致双重释放或访问已释放内存

解决方案

使用原型模式之后

  1. 创建原型抽象类
classCharacterPrototype{public:virtual~CharacterPrototype(){}=default;virtualCharacterPrototype*clone()const=0;virtualvoiddisplay()const=0;virtualstd::stringgetName()const=0;virtualvoidsetName(std::string name)=0;};
  1. 具体原型类
classSunWuKong:publicCharacterPrototype{private:std::string name;inthealth;intattack;std::vector<std::string>skills;std::vector<Equipment*>equipment;public:SunWuKong(std::string name,inthealth,intattack):name(name),health(health),attack(attack){// 初始化技能skills.push_back("七十二变");skills.push_back("筋斗云");skills.push_back("火眼金睛");skills.push_back("法天象地");// 初始化装备equipment.push_back(newEquipment("金箍棒",1000));equipment.push_back(newEquipment("锁子黄金甲",500));equipment.push_back(newEquipment("凤翅紫金冠",300));equipment.push_back(newEquipment("藕丝步云履",200));}// 拷贝构造函数(采用深拷贝)SunWuKong(constSunWuKong&other){name=other.name;health=other.health;attack=other.attack;skills=other.skills;equipment.clear();for(auto&eq:other.equipment){equipment.push_back(eq->clone());}}// 拷贝赋值运算符(采用深拷贝)SunWuKong&operator=(constSunWuKong&other){if(this!=&other){name=other.name;health=other.health;attack=other.attack;skills=other.skills;equipment.clear();for(auto&eq:other.equipment){equipment.push_back(eq->clone());}}}// 克隆方法(核心)CharacterPrototype*clone()constoverride{returnnewSunWuKong(*this);// 调用拷贝构造函数}voidsetName(std::string name)override{this->name=name;}std::stringgetName()constoverride{returnname;}voiddisplay()constoverride{std::cout<<"name: "<<this->name<<" , "<<"health: "<<this->health<<" , "<<"attack: "<<this->attack<<" , "<<"skills: \n";for(constauto&skill:skills){std::cout<<skill<<" ";}std::cout<<"\n";std::cout<<"equipment:\n";for(constauto&eq:equipment){eq->display();}}~SunWuKong(){for(auto&eq:equipment){deleteeq;}}};
  1. 原型管理器
classPrototypeManager{private:std::unordered_map<std::string,CharacterPrototype*>prototypes;public:~PrototypeManager(){for(auto&pair:prototypes){deletepair.second;}}voidaddPrototype(std::string key,CharacterPrototype*prototype){prototypes[key]=prototype;}CharacterPrototype*getPrototype(std::string key){if(prototypes.find(key)!=prototypes.end()){returnprototypes[key]->clone();}returnnullptr;}};
  1. 使用
voidusePrototype(){// 1. 创建原型SunWukong*original=newSunWukong("齐天大圣孙悟空",1500,150);original->display();std::cout<<"\n--- 孙悟空吹毫毛变分身 ---\n";// 2. 创建多个分身std::vector<CharacterPrototype*>clones;for(inti=1;i<=30;i++){// 使用克隆方法创建分身CharacterPrototype*clone=original->clone();clone->setName("孙悟空分身"+to_string(i));clones.push_back(clone);}// 3. 分身展示for(auto&clone:clones){clone->display();}// 4. 清理内存for(auto&clone:clones){deleteclone;}deleteoriginal;}voidusePrototypeManager(){PrototypeManager manager;manager.addPrototype("孙悟空",newSunWuKong("齐天大圣孙悟空",1500,150));// 从管理器获取原型并克隆autocloneFromManager=manager.getPrototype("sunwukong");if(cloneFromManager){cloneFromManager->setName("管理器中克隆的分身");cloneFromManager->display();deletecloneFromManager;}}voidcomparison(){autostart1=std::chrono::high_resolution_clock::now();// 传统方式创建10000个分身std::vector<SunWuKong*>clones1;SunWuKong*original=newSunWuKong("齐天大圣",1000,100);for(inti=0;i<10000;i++){clones1.push_back(newSunWuKong("分身",1000,100));}autoend1=std::chrono::high_resolution_clock::now();autostart2=std::chrono::high_resolution_clock::now();// 原型模式创建10000个分身std::vector<CharacterPrototype*>clones2;for(inti=0;i<10000;i++){clones2.push_back(original->clone());}autoend2=std::chrono::high_resolution_clock::now();std::cout<<"传统方式耗时: "<<std::chrono::duration_cast<std::chrono::milliseconds>(end1-start1).count()<<"ms\n";std::cout<<"原型模式耗时: "<<std::chrono::duration_cast<std::chrono::milliseconds>(end2-start2).count()<<"ms\n";}

附上UML图:

二、总结

2.1、与传统方式进行对比

特点传统创建方式原型模式
性能低,每次都要执行完整初始化高,一次初始化,多次复制
内存每个对象独立内存可共享不变部分
代码复杂度高,需要实现clone
灵活性高,可动态修改原型
适用场景对象创建简单对象创建复杂,批量创建

2.2、深拷贝 VS 浅拷贝

  • 浅拷贝:亦可称为值拷贝。将源对象的值拷贝到目标对象中,如果对象中某个成员是指针类型数据,并且是在堆上创建的,那么源对象和目标对象都指向同一块内存区域,此时如果其中一个对象释放了内存,那么另一个对象的指针就会变成野指针。
  • 深拷贝:在拷贝的时候,先开辟出与源对象大小一样的空间,然后将源对象的内容拷贝到新开辟的空间中。这样无论哪个对象释放内存,都不会影响另一个对象的正常使用。

2.3、原型模式 VS 工厂模式

  • 原型模式:通过克隆原型对象来创建新的对象,适用于创建复杂对象,特别是当对象的创建过程较为耗时或复杂时。
  • 工厂模式:通过工厂方法来创建对象,适用于创建不同类型的对象,特别是当对象的创建逻辑较为复杂时。

三、附加

由于C++语法的灵活性,原型模式实现可以有多种方式

1. 结合智能指针版–原型模式

// 使用智能指针和移动语义classSunWuKong1:publicCharacterPrototype{private:string name;inthealth;intattack;vector<string>skills;vector<unique_ptr<Equipment>>equipment;// 使用unique_ptrpublic:SunWuKong1(string name,inthealth,intattack):name(name),health(health),attack(attack){// 初始化技能skills.push_back("七十二变");skills.push_back("筋斗云");skills.push_back("火眼金睛");skills.push_back("法天象地");// 初始化装备equipment.push_back(newEquipment("金箍棒",1000));equipment.push_back(newEquipment("锁子黄金甲",500));equipment.push_back(newEquipment("凤翅紫金冠",300));equipment.push_back(newEquipment("藕丝步云履",200));}// 使用移动构造函数提高效率SunWuKong1(SunWuKong1&&other)noexcept:name(move(other.name)),health(other.health),attack(other.attack),skills(move(other.skills)),equipment(move(other.equipment)){}CharacterPrototype*clone()constoverride{// 先创建一个副本autoclone=make_unique<SunWuKong1>(name,health,attack);// 深拷贝equipmentfor(constauto&eq:equipment){clone->equipment.push_back(make_unique<Equipment>(*eq));}returnclone.release();}};

2. 结合函数模板,通过注册的方式–原型模式

classPrototypeRegistry{private:staticunordered_map<string,function<unique_ptr<CharacterPrototype>()>>registry;public:staticvoidregisterPrototype(conststring&key,function<unique_ptr<CharacterPrototype>()>creator){registry[key]=move(creator);}staticunique_ptr<CharacterPrototype>clone(conststring&key){if(autoit=registry.find(key);it!=registry.end()){returnit->second();}returnnullptr;}};
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 18:48:48

【MongoDB实战】第12章 测试与部署:从开发到生产(python实战完善版)

文章目录 《MongoDB实战入门》第12章 测试与部署:从开发到生产(python实战完善版) 12.1 MongoDB单元测试 12.1.1 环境准备 12.1.2 核心代码实现(覆盖CRUD+聚合+事务) 第一步:编写待测试的MongoDB业务操作类 第二步:编写单元测试用例 第三步:运行单元测试 12.2 生产环境…

作者头像 李华
网站建设 2026/5/20 10:49:57

基于SVPWM改进的异步电机/感应电机直接转矩控制:解决传统DTC转矩纹波大的问题“参考文...

基于SVPWM改进的异步电机/感应电机直接转矩控制针对传统DTC转矩纹波较大的问题&#xff0c;采用基于SVPWM发波方式去替换滞环离线开关表生成脉冲的方法&#xff0c;在一定程度上改善纹波较大的问题。 提供对应的参考文献;老铁们&#xff0c;玩过电机控制的都知道传统DTC那暴脾气…

作者头像 李华
网站建设 2026/5/20 18:27:41

10/10的AI论文工具推荐:覆盖数学建模复现率99%与自动排版

还在为论文写作头痛&#xff1f;特别是数学建模的优秀论文复现与排版&#xff0c;时间紧、任务重&#xff0c;AI工具能帮上大忙吗&#xff1f;今天&#xff0c;我们评测10款热门AI论文写作工具&#xff0c;帮你精准筛选最适合的助手。aibiye&#xff1a;专注于语法润色与结构优…

作者头像 李华
网站建设 2026/5/20 15:55:38

9 个降AI率工具,本科生高效降AIGC指南

9 个降AI率工具&#xff0c;本科生高效降AIGC指南 AI降重工具&#xff1a;高效降低AIGC率&#xff0c;让论文更自然 在当今学术写作中&#xff0c;越来越多的本科生开始使用AI生成内容来辅助论文写作。然而&#xff0c;随之而来的AIGC率过高、查重率偏高以及AI痕迹明显等问题&a…

作者头像 李华
网站建设 2026/5/21 10:40:59

BetterYeah智能体开发:插件概述

什么是插件当前大多数大模型使用的都是陈旧的语料进行训练&#xff0c;真实场景中&#xff0c;我们往往需要外部的数据来与LLM交互。插件是BetterYeah AI平台封装好提供给用户的内置扩展功能&#xff0c;它可以帮助用户轻松连接外部数据&#xff0c;和大模型协同构建更强大的功…

作者头像 李华
网站建设 2026/5/20 22:04:23

wsl使用git

前言&#xff1a;文章类型 > 笔记 安装git sudo apt-get install git 查看版本&#xff08;只用前面那句就行&#xff09; git --version; git credential-manager --version 用户配置 git config --global user.name "Your Name" git config --global user…

作者头像 李华