news 2026/6/9 6:06:19

原型模式-创建型

作者头像

张小明

前端开发工程师

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/6/9 2:03:17

揭秘大模型深度研究:从多智能体协作到结构化报告生成的全流程

深度研究(Deep Research)已成为现代大模型平台的标准能力&#xff0c;通过多智能体协作完成长时间研究任务。文章解析了其高层架构(编排者、子代理、综合与引用代理)&#xff0c;对比了OpenAI、Gemini、Claude等平台的实现差异&#xff0c;详细阐述了从用户查询、初始规划、并行…

作者头像 李华
网站建设 2026/6/7 17:43:30

2026版大模型应用开发全攻略:零基础入门到精通,一篇文章搞定,非常详细收藏这一篇就够!

“ 大语言模型应用开发流程包括筛选应用场景、企业知识管理、训练场景大模型、业务系统融合、大模型安全体系建设、持续改进体验等多个环节。通过将AI智能体集成到数字化系统中&#xff0c;将业务数字化系统升级为智能化系统&#xff0c;从而实现人类员工与数字员工的高效协作。…

作者头像 李华
网站建设 2026/6/2 13:55:10

经典算法题型之俄罗斯套娃信封问题(一)

我们先来看题目描述:给定一些标记了宽度和高度的信封&#xff0c;宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候&#xff0c;这个信封就可以放进另一个信封里&#xff0c;如同俄罗斯套娃一样。请计算最多能有多少个信封能组成一组“俄罗斯…

作者头像 李华
网站建设 2026/6/9 18:35:10

AN-93双麦降噪远场拾音模块技术解析:从算法到落地的全维度突破

AN-93双麦模组规格书点击查看 在语音交互技术全面渗透的当下&#xff0c;远场拾音与噪声抑制能力已成为衡量音频设备性能的核心指标。单麦方案因无法区分空间声源信息&#xff0c;难以应对复杂噪声环境&#xff1b;多麦方案则普遍面临成本高昂、体积偏大、集成难度较高的痛点。…

作者头像 李华