user1905391
user1905391

Reputation: 923

What's the point of the Prototype design pattern?

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?

Upvotes: 82

Views: 30124

Answers (9)

profPlum
profPlum

Reputation: 498

Most of these answers are quite theoretical... I'd like to give a concrete example where the prototype pattern is so useful that it's obviously the best design choice without any comparable alternatives.

I am developing a Bayesian Deep Learning library. It is inspired by BayesianTorch's simple dnn_to_bnn() function/interface, which can convert certain neural networks into Bayesian ones. But only RNNs, CNNs and MLPs (not e.g. Transformers) are supported!

My version of dnn_to_bnn() is special because it fully embraces the prototype pattern. I don't need to manually implement numerous Bayesian sub-classes of common layer types. I just re-parameterize an already constructed model in-place. So I can support all possible neural network architectures with about 1/15th of the code BayesianTorch uses!!

And it gets better! In a Bayesian setting this pattern allows you to set your bayesian priors based on a pre-trained model's weights. Which is the only way I can think of that would make sense to use an informative prior in deep learning.

Upvotes: 0

some_groceries
some_groceries

Reputation: 1192

Prototype design pattern produces a cloneable object, can be used under following situations

1). when creating objects is expensive and the data held by the object wont go stale or stale data can be mitigated. the data held by the object might be queried from a database, or requested through http, or calculated with a long running CPU process, in such situations cloning an immutable object is beneficial but not at the expense of having stale data.

2). some times it might not be programmatically possible to recreate an object, like state objects or snapshots or DOM structures, you also wouldn't be able to mutate the original object because its shared and you cannot sensibly persist the object, in such situations cloning an immutable object is beneficial but not at the expense of having stale data.

3). you might want to have the exact copy of a dataset for testing on various different environments or when you need to have default values for object properties, cloning would help here.

Upvotes: 1

davidXman
davidXman

Reputation: 31

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.

Upvotes: 2

marcus erronius
marcus erronius

Reputation: 3693

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.

Upvotes: 59

Ethan Hearne
Ethan Hearne

Reputation: 169

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.

Upvotes: 16

Andy
Andy

Reputation: 89

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.

Upvotes: 1

Michael Zheng
Michael Zheng

Reputation: 110

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.

Upvotes: -1

Mark Pauley
Mark Pauley

Reputation: 1485

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.

Upvotes: 45

user2328970
user2328970

Reputation: 99

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.

Upvotes: 7

Related Questions