Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 18 | Comments: 81

filter by tags archive

Design patterns in the test of timePrototype

time to read 3 min | 414 words

Create objects based on a template of an existing object through cloning.

More about this pattern.

This is how it looks like:

Prototype Example

Surprisingly enough, there are very few useful concrete examples of this, even in the literature. A lot of the time you see reference to ConcreteImplA and ConcreteImplB.

The original impetus for the Prototype pattern was actually:

  • avoid subclasses of an object creator in the client application, like the abstract factory pattern does.
  • avoid the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) when it is prohibitively expensive for a given application.

That is actually quite interesting. As I mentioned in the Factory Method analysis post, I like the notion of using Factory Delegate (and thus avoiding subclassing) quite a lot. This is usually useful for behavioral objects, that contains little state (it would be more accurate to say that their state is behavior, such as a class that mostly contains delegate members for different things). But for those sort of things, you usually don’t really need to modify them after the fact, so there isn’t much of a prototype here.

The second reasoning is not relevant for most things today. The cost of new is so near zero to be effectively meaningless.

But something that isn’t mentioned about this pattern is that it is very useful for multi threading. The notion of being able to handle a cloned object that can be modified independently of its original is key in things like caches, as you can see in the code above. We make heavy use of that internally inside RavenDB, for example, although we choose a slight more complex (and performant) route.

A key observation about this is that Prototype assumes long lives objects. Because otherwise, there wouldn’t be the prototype instance to clone from. In wide variety of applications today, that is simply not the case. Most of our objects live only for a single request. And anything whose lifetime is longer than a single request is usually persisted to a stable storage, rendering the basis for the Prototype pattern existence moot.

Recommendation: This is still a useful pattern for a limited number of scenarios. In particular, the ability to hand out a copy of the instance from a cache means that we don’t have to worry about multi threading. That said, beyond this scenario, I haven’t found many other uses for this.

More posts in "Design patterns in the test of time" series:

  1. (21 Jan 2013) Mediator
  2. (18 Jan 2013) Iterator
  3. (17 Jan 2013) Interpreter
  4. (21 Nov 2012) Command, Redux
  5. (19 Nov 2012) Command
  6. (16 Nov 2012) Chain of responsibility
  7. (15 Nov 2012) Proxy
  8. (14 Nov 2012) Flyweight
  9. (09 Nov 2012) Façade
  10. (07 Nov 2012) Decorator
  11. (05 Nov 2012) Composite
  12. (02 Nov 2012) Bridge
  13. (01 Nov 2012) Adapter
  14. (31 Oct 2012) Singleton
  15. (29 Oct 2012) Prototype
  16. (26 Oct 2012) Factory Method
  17. (25 Oct 2012) Builder
  18. (24 Oct 2012) A modern alternative to Abstract Factory–filtered dependencies
  19. (23 Oct 2012) Abstract Factory

Comments

mjanoska

Hi, actually I found immutable objects (doing functional style in .Net) quite useful. As I see once you have immutable-s (like a horrible immutable App Viewmodel :-) ) cloning comes into the picture naturally (ok in case of simple regeneration of the immutable sub trees changed). Also to make say something about .Net support there's MemberwiseClone method and ICloneable interface.

Cheers, Miklos

David

How about in the implementation of move semantics for C++ 11?

Michael L Perry

I have found two uses for this pattern in production. Both have to do with retaining identity while specifying the object you want by example.

The first example is object recycling. In Update Controls, a dependency-tracking MVVM framework, you specify a dependent collection using Linq. When the results change -- for example one object is added to the collection -- the entire query is re-run. Update Controls will compare the results of the query to the objects already in the list, and recycle those that are equal. This lets it figure out what has been inserted, deleted, or reordered while still retaining the identity of the untouched objects. This keeps data-bound lists from scrolling to the top or losing their selection. The query results are used as a prototype.

The second example is persistence identity. In Correspondence, a collaboration framework, you call a method to persist an object. If that object already exists, then the existing one is returned. If not, it returns the parameter. By using the parameter as a prototype, this method retains the identity of an object in memory, relative to the object on disk.

Retaining identity is important. The prototype pattern accomplishes that.

Rohit

Prototype pattern can also be combined along with AbstractFactory to create objects.

Christian Schlichtherle

I think the Prototype pattern is generally useful with mutable objects of all kind, not only in multithreading environments. It basically enables you to make a protective copy when a mutable object is exchanged between a caller and a callee. The advantage of the prototype pattern is then that the protective copy is controlled by the original object, i.e. it defines the class of the object to create as well as all details (shallow clone, deep clone etc). You can't have so much control with other creational patterns.

On the cons side, implementing Cloneable creates an obligation for any sub class, so it should be used with care.

David Waite

The Java "Properties" class is a prototype I believe. You also have prototype based languages such as Java, Lua and Io - in these there is no differentiation between a class and an object, as a 'class' is just a prototype which is used to create a new object.

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

  1. The insidious cost of allocations - 18 hours from now
  2. Buffer allocation strategies: A possible solution - 4 days from now
  3. Buffer allocation strategies: Explaining the solution - 5 days from now
  4. Buffer allocation strategies: Bad usage patterns - 6 days from now
  5. The useless text book algorithms - 7 days from now

And 1 more posts are pending...

There are posts all the way to Sep 11, 2015

RECENT SERIES

  1. Find the bug (5):
    20 Apr 2011 - Why do I get a Null Reference Exception?
  2. Production postmortem (10):
    03 Sep 2015 - The industry at large
  3. What is new in RavenDB 3.5 (7):
    12 Aug 2015 - Monitoring support
  4. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats