Многие другие ответы здесь говорят об экономии затрат на клонирование уже настроенного объекта, но я хотел бы остановиться на другой «точке» шаблона прототипа. В некоторых языках, где классы рассматриваются как объекты первого класса, вы можете настроить тип объекта, создаваемого клиентом во время выполнения, просто передав ему имя класса. В таких языках, как C ++, где классы не рассматриваются как объекты первого класса, шаблон «Прототип» позволяет добиться того же эффекта.
Например, предположим, что у нас есть 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
на показного знаменитого шеф-повара. Это означает, что он / она должны new
разные блюда в prepareMeal()
. Мы хотели бы изменить метод, чтобы типы блюд, которые получает new
от Chef
, можно было указывать в качестве параметров. В других языках, где классы являются объектами первого класса, мы можем просто передать имена классов в качестве параметров методу. Мы не можем сделать это в C ++, поэтому мы можем извлечь выгоду из шаблона прототипа:
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, так почему бы просто не использовать его? Поскольку шаблон Factory Method потребует иерархии классов-создателей, которые отражают иерархию создаваемых продуктов; то есть нам понадобится MozzarellaSticksWithKetchupCreator
с make()
методом, HockeyPuckHamburgerWithSoggyFriesCreator
с make()
методом и так далее. Таким образом, вы можете рассматривать шаблон прототипа просто как один из способов уменьшить избыточность кода, часто вносимую шаблоном Factory Method.
Этот аргумент взят из книги Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования, также известной как «Банда четырех».
person
Ethan Hearne
schedule
21.06.2018