哪位大佬帮我看看关于“原型设计模式”的问题
写作原因:
我需要了解原型模式,但网上的说法是:通过一个clone方法来创建对象。然而,这并没有解答关于“效率”的问题:
以下是以怪物游戏和深拷贝为例来说明的:
- 为什么使用这种模式来创建大量怪物效率会更高?难道不是都通过new来创建的吗?自定义的clone方法难道不是在底层调用new,与直接调用new相比效率有显著差异吗?
- 无论使用何种方法,每个怪物的大小都是一样的,为什么克隆拷贝会比新建实例更快?而且并没有使用多线程或多进程。
总体来说一个句话概况:为什么克隆拷贝会比新建实例更快?
于是我让GPT创建了一个 原型设计模式 的测试案例
#include <iostream>
#include <string>
#include <chrono>class ComplexObject {
private:std::string data;
public:ComplexObject(const std::string& d) : data(d) {// 模拟耗时的初始化操作std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "ComplexObject constructed with data: " << data << std::endl;}ComplexObject(const ComplexObject& other) : data(other.data) {std::cout << "ComplexObject copied with data: " << data << std::endl;}void setData(const std::string& newData) {data = newData;}void printData() {std::cout << "Data: " << data << std::endl;}
};class ObjectPrototype {
private:ComplexObject* prototype;
public:ObjectPrototype(ComplexObject* obj) : prototype(obj) {}ComplexObject* clone() {// 通过复制构造函数来创建新对象return new ComplexObject(*prototype);}
};int main() {// 创建原型对象ComplexObject* prototype = new ComplexObject("Prototype Data");// 使用原型对象创建新对象ObjectPrototype* objPrototype = new ObjectPrototype(prototype);// 复制原型对象来创建新对象ComplexObject* newObj1 = objPrototype->clone();ComplexObject* newObj2 = objPrototype->clone();newObj1->printData();newObj2->printData();delete prototype;delete newObj1;delete newObj2;delete objPrototype;return 0;
}
代码分析
ComplexObject 的 拷贝构造速度>构造函数速度 ,因为构造函数中有个延时sleep的操作。所以,原型设计模式的克隆是通过拷贝构造函数实现,而拷贝构造速度>构造函数速度 ,所以 clone > new 。这确实没问题。
代码总结
GPT认为:速度快需要 拷贝构造速度>构造函数速度 才能加速,否则无法加速。
仍然无法加速的情况
上述代码没有考虑到深拷贝的情况。在深拷贝时候,拷贝构造速度和构造函数速度可能差不多,就无法加速了。比如下面的代码
案例:深拷贝 + 原型设计模式对比实验
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <vector>constexpr auto N = 10000;
constexpr auto NUMBER_OF_People = 1000 ;class ComplexObject {
private:long long data;std::vector<long long> * m_pNumbers = new std::vector<long long>;
public:ComplexObject(const long long& d) : data(d) {// 用创建大数组模拟耗时的初始化操作for (int i = 0; i < N; i ++){m_pNumbers->push_back(i);}(*m_pNumbers)[0] = data;std::cout << "ComplexObject constructed with data: " << data << std::endl;}ComplexObject(const ComplexObject& other, long long id) : data(other.data) {// 用深拷贝大数组模拟耗时的初始化操作for (int i = 0; i < N; i++){m_pNumbers->push_back((*(other.m_pNumbers))[i]);}(*m_pNumbers)[0] = id;std::cout << "ComplexObject copied with data: " << (*m_pNumbers)[0] << std::endl;}void printData() {std::cout << "Data: " << (*m_pNumbers)[0] << std::endl;}
};class ObjectPrototype {
private:ComplexObject* prototype;
public:ObjectPrototype(ComplexObject* obj) : prototype(obj) {}ComplexObject* clone(int id) {// 通过复制构造函数来创建新对象return new ComplexObject(*prototype,id);}
};// 使用原型设计模式的情况
int main1() {std::cout << "Test prototype begin" << std::endl << std::endl;// 创建原型对象ComplexObject* prototype = new ComplexObject(1);// 使用原型对象创建新对象ObjectPrototype* objPrototype = new ObjectPrototype(prototype);std::vector< ComplexObject*> g_vecPeople;// 复制原型对象来创建新对象auto start = std::chrono::high_resolution_clock::now();for (int i = 2; i < NUMBER_OF_People; i++){ComplexObject* newObj = objPrototype->clone(i);g_vecPeople.push_back(newObj);}auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);double durationInSeconds = duration.count() / 1000000.0; // 转换为秒std::cout << "Function execution time: " << durationInSeconds << " seconds" << std::endl;for (std::vector< ComplexObject*>::iterator it = g_vecPeople.begin(); it != g_vecPeople.end(); it++){if (*it){delete* it;*it = nullptr;}}g_vecPeople.clear();delete prototype;delete objPrototype;return 0;
}// 一般的情况
int main() {std::cout << "Test STD begin" << std::endl << std::endl;// 创建原型对象ComplexObject* prototype = new ComplexObject(1);std::vector< ComplexObject*> g_vecPeople;// 复制原型对象来创建新对象auto start = std::chrono::high_resolution_clock::now();for (int i = 2; i < NUMBER_OF_People; i++){ComplexObject* newObj = new ComplexObject(i);g_vecPeople.push_back(newObj);}auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);double durationInSeconds = duration.count() / 1000000.0; // 转换为秒std::cout << "Function execution time: " << durationInSeconds << " seconds" << std::endl;for (std::vector< ComplexObject*>::iterator it = g_vecPeople.begin(); it != g_vecPeople.end(); it++){if (*it){delete* it;*it = nullptr;}}g_vecPeople.clear();return 0;
}
代码分析
上述代码构造了一种 拷贝构造速度==构造函数速度 的情况,发现没有实现加速。
得到一个奇怪的结论:深拷贝情况下,创立多个对象,似乎原型设计模式无法加速。
更新一下GPT的回答
问:
如果ComplexObject 类的 拷贝构造函数的 和 构造函数速度相同,那使用原型设计模式创建多个对象还有加速的效果吗?
答:
原型设计模式的主要目的是通过复制现有对象来创建新对象,从而避免了使用常规的构造函数来初始化新对象的开销。如果复制构造函数的速度与常规构造函数相同,那么在性能方面可能不会有太大的加速效果。
然而,即使复制构造函数的速度与常规构造函数相同,使用原型设计模式仍然可以带来一些优势:
减少初始化时间:尽管构造函数的速度相同,但使用原型模式可以避免一些初始化步骤,因为新对象可以直接从现有对象复制而来,而不需要重新执行构造函数中的初始化操作。
避免重复的计算和初始化:如果对象的创建涉及到复杂的计算或初始化过程,使用原型模式可以避免重复执行这些计算和初始化步骤,因为新对象可以直接从现有对象复制而来。
灵活性:使用原型模式可以更灵活地创建对象,因为可以根据现有对象的状态来创建新对象,而不受构造函数的限制。
总的来说,尽管在速度方面可能没有显著的加速效果,但使用原型模式仍然可以提高代码的性能和灵活性。