ONNX ScatterND算子保姆级解读:从官方定义到Python/NumPy手写实现
2026/6/5 21:16:49
原型实例指定创建对象的种类,并通过拷贝这些原型,创建新的对象。即克隆,细胞分裂等。
通过复制现有对象(原型)来创建新对象,而不是通过new新建实例
创建角色,以孙悟空为例
// 装备类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;}}问题点:
使用原型模式之后
classCharacterPrototype{public:virtual~CharacterPrototype(){}=default;virtualCharacterPrototype*clone()const=0;virtualvoiddisplay()const=0;virtualstd::stringgetName()const=0;virtualvoidsetName(std::string name)=0;};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;}}};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;}};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图:
| 特点 | 传统创建方式 | 原型模式 |
|---|---|---|
| 性能 | 低,每次都要执行完整初始化 | 高,一次初始化,多次复制 |
| 内存 | 每个对象独立内存 | 可共享不变部分 |
| 代码复杂度 | 低 | 高,需要实现clone |
| 灵活性 | 低 | 高,可动态修改原型 |
| 适用场景 | 对象创建简单 | 对象创建复杂,批量创建 |
// 使用智能指针和移动语义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();}};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;}};