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: 5,953 | Comments: 44,399

filter by tags archive

Design patterns in the test of timeFactory Method


Define an interface for creating an object, but let the classes that implement the interface decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses.

More on this pattern.

Here is some sample code:

   1: public class MazeGame {
   2:   public MazeGame() {
   3:      Room room1 = MakeRoom();
   4:      Room room2 = MakeRoom();
   5:      room1.Connect(room2);
   6:      AddRoom(room1);
   7:      AddRoom(room2);
   8:   }
   9:  
  10:   protected virtual Room MakeRoom() {
  11:      return new OrdinaryRoom();
  12:   }
  13: }

This pattern is quite useful, and is in fairly moderate use. For example, you can take a look at WebClient.GetWebRequest, which is an exact implementation of this pattern. I like this pattern because this allows me to keep the Open Closed Principle, I don’t need to modify the class, I can just inherit and override it to change things.

Still, this is the class method. I like to mix things up a bit and not use a virtual method, instead, I do things like this:

   1: public class MazeGame {
   2:    public Func<Room> MakeRoom = () => new OrdinaryRoom();
   3: }

This allows me change how we are creating the room without even having to create a new subclass. In fact, it allows me to change this per instance.

I make quite a heavy use of this in RavenDB, for example. The DocumentConventions class is basically built of nothing else.

Recommendation: Go for the lightweight Factory Delegate approach. As with all patterns, use with caution and watch for overuse & abuse. In particular, if you need to manage state between multiple delegate, fall back to the overriding approach, because you can keep the state in the subclass.

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

Markus Zywitza

I'd rather go for the delegate approach, as it is recommended to not access virtual methods from the constructor, as instance state might not be initialized by the time it is called.

The protected instance variable with the delegate is already populated before the base class constructor is called if it was initialized in the code.

But if MakeRoom is set in the child class constructor instead, the base class constructor will instead use the default method implementation.

Nasty to debug and brittle, so I wouldn't recommend either approach.

Bartek

I think calling virtual member from constructor is not a good idea. It might work in this example but in general it should be avoided: http://msdn.microsoft.com/en-us/library/ms182331(v=vs.80).aspx

SteveR

Following the example of WebClient.CreateRequest, you can easily avoid the concerns about calling virtual methods in the constructor by implementing a static Factory Method on the base class instead. In cases where the implementation of the overridden method can depend upon some state in a subclass this works out well, but the delegate approach is nice and light-weight whilst also being more in line with the maxim of preferring composition over inheritance.

SteveR

Of course, you lose the Open-Closed ability..

Jimmy Zimms

@Bartek/Markus

I think this is more a case of succinct for blogging purposes than actually how Oren suggests a factory should be written in practice. What you describe has multiple known "fixes" or techniques for avoiding that situation which can be as simple (or naive as you wish) as using a Lazy there to side step the problem to a method to "start the game" to something totally full blown as appropriate for the problem area. More importantly to discuss here is the concept he points about about leveraging delegates (with sane default implementations automatically initialized) to callback into to do work.

@SteveR No sure how you think that this isn't totally amenable to following the OCP. Here in this example is, again, what I assume to be simple code to illustrate the core concept succinctly. To support the OCP all one would need to do is have a core method that does whatever the work is that invokes the supplied delegate for whatever that part of the extensiblity is designed to do. This is what we referred to in the WF4 team as "basic swiss cheese" architecture (a toungue in cheek term). Nothing new here, just common sense =D

SteveR

@Jimmy: I was referring to the static Factory Method approach on the base class to avoid the concern about calling virtual methods from a constructor. You pretty much need to know the available subclasses ahead of time or change the method when a new one is introduced, hence the OCP violation.

Jimmy Zimms

@SteveR.

Ahh my bad. I was reading that as two seperate thoughts, the latter directed at Oren. +D

Ken
Ken

@SteveR: With a small tweak, the static Factory Method approach can still follow OCP. For example, WebRequest.Create is a factory method. By registering a new factory with WebRequest.RegisterPrefix, WebRequest.Create can return my own objects. I use this technique to mock WebRequest objects. See answers to http://stackoverflow.com/q/87200 for more info.

Dmitry

You can have a protected virtual "Create" method which can be called from the static factory method in the base class.

You can even use a Java-style nested builder class to create the objects. It will have access to the class internals and will not violate the single responsibility principal.

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

  1. Comparing developers - 5 hours from now

There are posts all the way to Jun 30, 2015

RECENT SERIES

  1. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
  2. Special Offer (2):
    27 May 2015 - 29% discount for all our products
  3. RavenDB Sharding (3):
    22 May 2015 - Adding a new shard to an existing cluster, splitting the shard
  4. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  5. Interview question (2):
    30 Mar 2015 - fix the index
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats