What's the point of the Prototype design pattern?

Design PatternsPrototype Pattern

Design Patterns Problem Overview


So I'm learning about design patterns in school. Today I was told about the 'Prototype' design pattern.

I must be missing something, because I don't see the benefits from it. I've seen people online say it's faster than using new but this doesn't make sense; at some point, regardless of how the new object is created, memory needs to be allocated for it.

Doesn't this pattern run in the same circles as the 'chicken or egg' problem? Since the Prototype pattern essentially is just cloning objects, at some point the original object must be created itself (i.e. not cloned). This would mean that I need to have an existing copy of every object I want to clone already ready to clone?

Can anyone explain what the use of this pattern is?

Design Patterns Solutions


Solution 1 - Design Patterns

The prototype pattern has some benefits, for example:

  • It eliminates the (potentially expensive) overhead of initializing an object
  • It simplifies and can optimize the use case where multiple objects of the same type will have mostly the same data

For example, say your program uses objects that are created from data parsed from mostley unchanging information retrieved over the network. Rather than retrieving the data and re-parsing it each time a new object is created, the prototype pattern can be used to simply duplicate the original object whenever a new one is needed.

Also, say that object may have data that uses up large amounts of memory, such as data representing images. Memory can be reduced by using a copy-on-write style inheritance, where the original, unduplicated data is shown until the code attempts to change that data. Then, the new data will mask to reference to the original data.

Solution 2 - Design Patterns

The Prototype pattern is a creation pattern based on cloning a pre-configured object. The idea is that you pick an object that is configured for either the default or in the ballpark of some specific use case and then you clone this object and configure to your exact needs.

The pattern is useful to remove a bunch of boilerplate code, when the configuration required would be onerous. I think of Prototypes as a preset object, where you save a bunch of state as a new starting point.

Solution 3 - Design Patterns

Many of the other answers here talk about the cost savings of cloning an already-configured object, but I would like to expand on the other "point" of the Prototype pattern. In some languages, where classes are treated as first-class objects, you can configure what type of object gets created by a client at runtime by simply passing it the class name. In languages like C++, where classes are not treated as first-class objects, the Prototype pattern allows you to achieve the same effect.

For example, let's say we have a Chef in a restaurant whose job is to make and serve meals. Let's say the Chef is underpaid and disgruntled, so he makes dishes like the following:

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...
        }
};

Now let's say we want to change the Chef to be an ostentatious celebrity chef. This means he/she has to new different dishes in prepareMeal(). We would like to modify the method so that the types of meals that get new by the Chef can be specified as parameters. In other languages where classes are first class objects, we can simply pass the class names as parameters to the method. We can't do this in C++, so we can benefit from the prototype pattern:

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...
        }
};

Note that a clone() method creates an instance of the derived type, but returns a pointer to the parent type. This means we can change the type of object that gets created by using a different derived type, and the client won't know the difference. This design now allows us to configure a Chef -- the client of our Prototypes -- to make different types of dishes at runtime:

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);

You may wonder that used this way, the Prototype pattern buys you the same thing as the Factory Method pattern, so why not just use that? Because the Factory Method pattern would require a hierarchy of creator classes that mirror the hierarchy of products being created; i.e. we would need a MozzarellaSticksWithKetchupCreator with a make() method, a HockeyPuckHamburgerWithSoggyFriesCreator with a make() method, and so on. You could, therefore, view the Prototype pattern simply as one way to alleviate the code redundancy often introduced by the Factory Method pattern.

This argument is drawn from Design Patterns: Elements of Reusable Object-Oriented Software, a.k.a. the "Gang of Four" book.

Solution 4 - Design Patterns

If you want to create an object but do not want to go through the expensive object creation procedure where network or database calls are made, then use the prototype pattern. Just create a copy of the object and do your changes on it.

Solution 5 - Design Patterns

using prototype pattern is completely depends on the your problem. In most of usual cases there is not any difference between cloning and creating new object. BUT if you are doing some complex or time consuming operations in constructor or when setting a property and it must do complex and time consuming operations , prototype pattern will help us. Because copying objects from old instance to new instance is easier and its performance is higher.(Deep cloning). So this pattern is more compatible with objects that their state is not changed for long time. Completely analyze your problem before using this pattern.

Solution 6 - Design Patterns

If you have a requirement, where you need to populate or use the same data containing Object repeatable

and

it is not possible to build from existing Object for example [ Building Object using Network Stream ] or

to build an Object is time-consuming [Building a Big Object, by getting data from Database] then use this design pattern, as in this a Copy the existing Object is created, this copy would be different from the Original Object and could be used just like Original one.

Solution 7 - Design Patterns

Compared with the abstract factory pattern, by using the prototype pattern, you don't have to have a big factory hierarchy, just a big product hierarchy.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1905391View Question on Stackoverflow
Solution 1 - Design Patternsmarcus erroniusView Answer on Stackoverflow
Solution 2 - Design PatternsMark PauleyView Answer on Stackoverflow
Solution 3 - Design PatternsEthan HearneView Answer on Stackoverflow
Solution 4 - Design Patternsuser2328970View Answer on Stackoverflow
Solution 5 - Design PatternsdavidXmanView Answer on Stackoverflow
Solution 6 - Design PatternsAndyView Answer on Stackoverflow
Solution 7 - Design PatternsMichael ZhengView Answer on Stackoverflow