views:

311

answers:

3

I am doing an in depth study on design patterns, and I came across prototype, which I didn't really study before. I have searched the web and several books, and there isn't a really good example of prototype that could find that isn't just clone. Is the design pattern of prototype basically a language feature of java and C# as clone?

A: 

Clone() is definitely part of it. I think the pattern also talks about there being ways to collect objects, iterate through them, and find the right one to clone. You also have to set up the objects to begin with.

Lou Franco
+3  A: 

Sorta. Clone() does a lot of what you want for Prototype purposes, but you can go much further with the pattern if you need to. See Steve Yegge's deep (and lengthy!) explanation, or study the Javascript object model.

David Seiler
That's not prototype -- (although it's definitely related) -- he's calling it the Properties Pattern. In JavaScript, the word "prototype" is used to describe part of this, and cloning is definitely involved, but I still think of them as different things. Prototype in GoF doesn't talk about the idea of dynamic properties.
Lou Franco
That's a fair point. I've always thought of Prototype as encompassing things like dynamic properties and iterability, just because if it doesn't it *is* basically Clone(), and that seems lame.
David Seiler
Wow, thanks for posting that blog entry. Very good read. I learned a lot from reading that. I agree it's not the prototype pattern described in the GoF book.
John Sonmez
+3  A: 

The Prototype pattern is much more than Clone. Clone semantics are broader, meaning the scalars/value fields of one object instance are duplicated in a new instance such that they have the equivalent state but occupy different locations in memory. Clone can be used to support many different needs.

The Prototype pattern incorporates Clone specifically into resolving the larger problem of separating object construction from object use. Prototype semantics state that the only (or at least the supported/preferred) method for constructing a new object of required behavior is by Cloning a particular instance, known as the prototype instance. These prototype instances can live in a prototype factory, which is implemented to create new instances by calling Clone on the prototype instances. The prototype instances can be initialized via dependency injection. The injecting code is the only code that needs to know how to build the prototype instances, and this effectively becomes the real factory code.

Hopefully the following example factory class clarifies the crux of the pattern:

public class PrototypeWidgetFactory : IWidgetFactory
{
  public PrototypeWidgetFactory(PrototypeWidget scenarioA, PrototypeWidget scenarioB, PrototypeWidget scenarioC) 
  {
    _scenarioA = scenarioA;
    _scenarioB = scenarioB;
    _scenarioC = scenarioC;
  }

  public Widget GetForScenarioA() { return _scenarioA.Clone(); }
  public Widget GetForScenarioB() { return _scenarioB.Clone(); }
  public Widget GetForScenarioC() { return _scenarioC.Clone(); }

  private PrototypeWidgetFactory _scenarioA;
  private PrototypeWidgetFactory _scenarioB;
  private PrototypeWidgetFactory _scenarioC;
}

An instance of this factory can be passed wherever IWidgetFactory is needed. The advantage is that you don't need a bunch of different factory classes for each behavior. In fact, for certain types of behavior, you don't even need a bunch of different classes if you just inject instances of the same type that are initialized differently into the prototype factory. In this case, the advantage is even greater in that the API doesn't bloat with a bunch of small classes that don't do much.

The drawback is that the injecting code needs to know how to construct the prototypes. This is brittle if there is a lot of complex logic involved in constructing the prototypes.

(Note: the Prototype pattern doesn't require that all methods on a prototype factory return the same type. I just made the example return only Widgets because that demonstrates the greater advantage of using prototypes to construct objects for particular behaviorwhen the objects are of one type but initialized differently.)

public class PrototypeDomainFactory : IDomainFactory
{
  public PrototypeDomainFactory(PrototypePerson personPrototype, PrototypeCompany companyPrototype, PrototypeWidget widgetPrototype) 
  {
    _personPrototype = personPrototype;
    _companyPrototype = companyPrototype;
    _widgetPrototype = widgetPrototype;
  }

  public Person GetPerson() { return _personPrototype.Clone(); }
  public Company GetCompany() { return _companyPrototype.Clone(); }
  public Widget GetWidget() { return _widgetPrototype.Clone(); }

  private PrototypePerson _personPrototype;
  private PrototypeCompany _companyPrototype;
  private PrototypeWidget _widgetPrototype;
}
gWiz