我正在尝试学习设计模式。我是一名C++程序员。目前,我正在处理原型模式。我可以将原型与工厂类型相关联。但是,工厂模式和原型模式之间存在很多差异。例如,在原型模式中,每个派生类都向基类/超类注册其原型。
但是,看着维基百科的文章 - 我无法理解以下几点。
-
原型模式可用于在需要新对象时简单地复制原始对象,而不是在每次创建新对象时检索数据并重新解析它。
-
避免以标准方式创建新对象的固有成本(例如,使用"new"关键字),因为对于给定的应用程序来说,新对象非常昂贵。
这是我创建的程序,用于演示C++中的原型模式。但是,我无法从中找到任何好处。为什么原型模式将有助于在此处快速创建对象。我可以看到对象每次都必须调用"new"。这是整个程序,如果您认为我没有正确实现原型模式,请纠正我。
很抱歉程序很长 - 但相信我,这很简单。
像工厂对象一样 - 这是原型类
-- basically an abstract.
class Itransport
{
public:
enum transportPacketType
{
udp,
tcp,
MAX
};
private:
static std::list<Itransport *> prototypesList;
protected:
virtual Itransport::transportPacketType getPacketType() = 0;
virtual Itransport* clone() = 0;
/** This will be called by the derived classes **/
static void registertoPrototypeList(Itransport *packet)
{
prototypesList.push_back(packet);
}
public:
virtual void showMessage() = 0;
static Itransport* makeClone(Itransport::transportPacketType packType)
{
std::list<Itransport *>::iterator it;
for(it = prototypesList.begin(); it != prototypesList.end(); it++)
{
if( (*it)->getPacketType() == packType )
{
return (*it)->clone();
}
}
}
virtual ~Itransport() = 0;
};
Itransport::~Itransport()
{
std::cout<<"Itransport Destructor called"<<std::endl;
}
std::list<Itransport *> Itransport::prototypesList;
这是 Itransport 数据包的具体类型 -
class udpPacket: public Itransport
{
private:
static udpPacket udpTransportPacket;
protected:
Itransport::transportPacketType getPacketType()
{
return Itransport::udp;
}
Itransport* clone()
{
return new udpPacket();
}
public:
void showMessage()
{
std::cout<<"This is a UDP Packet"<<std::endl;
}
udpPacket()
{
std::cout<<"UDP Packet Constructed"<<std::endl;
registertoPrototypeList(this);
}
~udpPacket()
{
std::cout<<"Destructor of udp called"<<std::endl;
}
};
static udpPacket udpTransportPacket;
这是客户端 -
int main()
{
Itransport *udpPacket;
Itransport *udpPacket2;
udpPacket = Itransport::makeClone(Itransport::udp);
udpPacket->showMessage();
udpPacket2 = Itransport::makeClone(Itransport::udp);
udpPacket2->showMessage();
delete udpPacket;
delete udpPacket2;
return 0;
}
我在这里找不到任何与"新"相关的好处。请对此进行一些说明。
我可以尝试解释第一点:
而不是每次新的数据时检索数据并重新解析它 对象被创建,原型模式可用于简单地 每当需要新对象时复制原始对象。
想象一下,一个电脑游戏必须创造很多怪物。假设在编译时不知道所有不同类型的怪物,但是您从一些输入数据中构造了特定类型的怪物,这些数据提供了有关怪物是什么颜色的信息,等等:
class Monster {
public:
Monster(InputDataHandle handle) {
// Retrieve input data...
// Parse input data...
}
void setPosition(Position);
};
然后每次你想要构造时,比如说一个红色的怪物,你必须检索数据并重新解析:
// Spawn a lot of red monsters
for (int i = 0; i != large_number; ++i) {
auto red = new Monster(red_monster_data); // Must retrieve data and re-parse!
red->setPosition(getRandomPosition());
game.add(red);
}
显然,这是低效的。解决该问题的一种方法是使用原型模式。你创建了一个"原型"红色怪物,每次你想要创建一个红色怪物的实例时,你只需复制原型,你不必检索和重新解析输入数据:
auto prototype_red_monster = new Monster(red_monster_data);
for (int i = 0; i != large_number; ++i) {
auto red = prototype_red_monster->clone();
red->setPosition(getRandomPosition());
game.add(red);
}
但是克隆功能是如何实现的呢?这就引出了我不太明白的第二点:
避免以标准方式创建新对象的固有成本 (例如,使用"new"关键字)当它过于昂贵时 给定的应用程序。
克隆函数从根本上必须为新对象分配内存并从自身复制数据。我不确定当他们谈论"new
关键字的固有成本"时,我是否知道他们指的是什么。这些示例在 Java 和 C# 中分别具有clone()
和MemberwiseClone()
。在这些语言中,您无需调用 new
。我不知道clone()
和MemberwiseClone()
是如何实现的,但我看不出他们如何"避免new
关键字的固有成本"。
在C++我们必须自己实现clone()
,它通常会使用 new
并使用复制构造函数:
Monster* clone() {
return new Monster(*this);
}
在这种情况下,复制构造函数比从头开始创建对象便宜得多。 在您的情况下,可能不是。
事实上,您无法从原型模式中找到任何好处,这可能意味着它不适合您的情况,并且最好使用不同的模式,例如对象池,蝇量级或抽象工厂模式。