哪位大佬帮我看看关于“原型设计模式”的问题
写作原因:
我需要了解原型模式,但网上的说法是:通过一个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 类的 拷贝构造函数的 和 构造函数速度相同,那使用原型设计模式创建多个对象还有加速的效果吗?
答:
原型设计模式的主要目的是通过复制现有对象来创建新对象,从而避免了使用常规的构造函数来初始化新对象的开销。如果复制构造函数的速度与常规构造函数相同,那么在性能方面可能不会有太大的加速效果。
然而,即使复制构造函数的速度与常规构造函数相同,使用原型设计模式仍然可以带来一些优势:
减少初始化时间:尽管构造函数的速度相同,但使用原型模式可以避免一些初始化步骤,因为新对象可以直接从现有对象复制而来,而不需要重新执行构造函数中的初始化操作。
避免重复的计算和初始化:如果对象的创建涉及到复杂的计算或初始化过程,使用原型模式可以避免重复执行这些计算和初始化步骤,因为新对象可以直接从现有对象复制而来。
灵活性:使用原型模式可以更灵活地创建对象,因为可以根据现有对象的状态来创建新对象,而不受构造函数的限制。
总的来说,尽管在速度方面可能没有显著的加速效果,但使用原型模式仍然可以提高代码的性能和灵活性。