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.
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:
- (21 Jan 2013) Mediator
- (18 Jan 2013) Iterator
- (17 Jan 2013) Interpreter
- (21 Nov 2012) Command, Redux
- (19 Nov 2012) Command
- (16 Nov 2012) Chain of responsibility
- (15 Nov 2012) Proxy
- (14 Nov 2012) Flyweight
- (09 Nov 2012) Façade
- (07 Nov 2012) Decorator
- (05 Nov 2012) Composite
- (02 Nov 2012) Bridge
- (01 Nov 2012) Adapter
- (31 Oct 2012) Singleton
- (29 Oct 2012) Prototype
- (26 Oct 2012) Factory Method
- (25 Oct 2012) Builder
- (24 Oct 2012) A modern alternative to Abstract Factory–filtered dependencies
- (23 Oct 2012) Abstract Factory
Comments
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.
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
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.
Of course, you lose the Open-Closed ability..
@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
@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.
@SteveR.
Ahh my bad. I was reading that as two seperate thoughts, the latter directed at Oren. +D
@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.
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