所以我在学校学习设计模式。今天我被告知了“原型”设计模式。
我一定是错过了什么,因为我看不到它的好处。我在网上看到人们说它比使用new更快,但这并不合理;在某些情况下,无论新对象是如何创建的,都需要为其分配内存。
这种模式与“鸡还是蛋”的问题不是在同一个圈子里运行吗?由于原型模式本质上只是克隆对象,因此在某些情况下,原始对象必须自己创建(即不克隆)。这意味着我需要准备好要克隆的每个对象的现有副本。
谁能解释一下这个模式的用法是什么?
发布于 2012-12-15 07:34:45
原型模式是一种基于克隆预配置对象的创建模式。这个想法是,您选择一个对象,该对象被配置为默认的或某个特定用例的大致情况,然后克隆该对象并根据您的确切需求进行配置。
当所需的配置很繁重时,该模式对于删除一堆样板代码很有用。我认为原型是一个预设对象,在这里你可以保存一堆状态作为一个新的起点。
发布于 2012-12-15 08:14:20
prototype模式有一些好处,例如:
的使用情形
例如,假设您的程序使用的对象是从网络上检索到的大多数不变信息解析出的数据创建的。无需每次创建新对象时检索数据并重新解析它,只要需要新对象,就可以使用原型模式简单地复制原始对象。
另外,假设对象可能具有占用大量内存的数据,例如表示图像的数据。可以通过使用写入时复制样式继承来减少内存,其中显示原始的、未复制的数据,直到代码尝试更改该数据为止。然后,新数据将屏蔽对原始数据的引用。
发布于 2018-06-21 23:34:16
这里的许多其他答案都谈到了克隆已经配置的对象的成本节约,但我想扩展原型模式的另一个“点”。在某些语言中,类被视为一级对象,您可以通过简单地向客户端传递类名来配置客户端在运行时创建的对象类型。在像C++这样的语言中,类不被视为第一类对象,Prototype模式允许您实现相同的效果。
例如,假设我们在一家餐馆有一个Chef,他的工作是制作和提供食物。假设Chef的薪水很低,而且心怀不满,所以他做了如下菜肴:
class Chef {
public:
void prepareMeal() const {
MozzarellaSticksWithKetchup* appetizer = new MozzarellaSticksWithKetchup();
// do something with appetizer...
HockeyPuckHamburgerWithSoggyFries* entree = new HockeyPuckHamburgerWithSoggyFries();
// do something with entree...
FreezerBurnedIceCream* dessert = new FreezerBurnedIceCream();
// do something with dessert...
}
};现在,假设我们想要将Chef更改为一个爱炫耀的名厨。这意味着他/她必须在prepareMeal()中new不同的菜肴。我们希望修改该方法,以便通过Chef获取new的用餐类型可以指定为参数。在其他语言中,类是第一类对象,我们可以简单地将类名作为参数传递给方法。我们不能在C++中做到这一点,所以我们可以从prototype模式中获益:
class Appetizer {
public:
virtual Appetizer* clone() const = 0;
// ...
};
class Entree {
public:
virtual Entree* clone() const = 0;
// ...
};
class Dessert {
public:
virtual Dessert* clone() const = 0;
// ...
};
class MozzarellaSticksWithKetchup : public Appetizer {
public:
virtual Appetizer* clone() const override { return new MozzarellaSticksWithKetchup(*this); }
// ...
};
class HockeyPuckHamburgerWithSoggyFries : public Entree {
public:
virtual Entree * clone() const override { return new HockeyPuckHamburgerWithSoggyFries(*this); }
// ...
};
class FreezerBurnedIceCream : public Dessert {
public:
virtual Dessert * clone() const override { return new FreezerBurnedIceCream(*this); }
// ...
};
// ...and so on for any other derived Appetizers, Entrees, and Desserts.
class Chef {
public:
void prepareMeal(Appetizer* appetizer_prototype, Entree* entree_prototype, Dessert* dessert_prototype) const {
Appetizer* appetizer = appetizer_prototype->clone();
// do something with appetizer...
Entree* entree = entree_prototype->clone();
// do something with entree...
Dessert* dessert = dessert_prototype->clone();
// do something with dessert...
}
};请注意,clone()方法创建派生类型的实例,但返回指向父类型的指针。这意味着我们可以更改通过使用不同的派生类型创建的对象的类型,而客户端不会知道差异。这种设计现在允许我们配置一个Chef --原型的客户端--在运行时制作不同类型的菜肴:
Chef chef;
// The same underpaid chef from before:
MozzarellaSticksWithKetchup mozzarella_sticks;
HockeyPuckHamburgerWithSoggyFries hamburger;
FreezerBurnedIceCream ice_cream;
chef.prepareMeal(&mozzarella_sticks, &hamburger, &ice_cream);
// An ostentatious celebrity chef:
IranianBelugaCaviar caviar;
LobsterFrittataWithFarmFreshChives lobster;
GoldDustedChocolateCupcake cupcake;
chef.prepareMeal(&caviar, &lobster, &cupcake);您可能想知道,通过这种方式,Prototype模式为您购买了与Factory Method模式相同的东西,那么为什么不直接使用它呢?因为工厂方法模式需要一个创建者类的层次结构来反映所创建的产品的层次结构;也就是说,我们需要一个具有make()方法的MozzarellaSticksWithKetchupCreator,一个具有make()方法的HockeyPuckHamburgerWithSoggyFriesCreator,等等。因此,您可以简单地将Prototype模式视为减轻Factory Method模式通常引入的代码冗余的一种方法。
这个论点来自于设计模式:可重用面向对象软件的元素,也就是。“四人帮”这本书。
https://stackoverflow.com/questions/13887704
复制相似问题