Design patterns in the test of timeBuilder
The intent of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so, the same construction process can create different representations.
The sample code that usually comes with this pattern is something like this:
1: PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();2: Cook cook = new Cook();3: cook.SetPizzaBuilder(hawaiianPizzaBuilder);
4: cook.ConstructPizza();
5: // create the product6: Pizza hawaiian = cook.GetPizza();
I find this sort of code to be extremely verbose and hard to read. Especially when we have a lot of options and things to do. Fluent Interfaces, however, are just an instance of the Builder pattern, and they are basically adding a modern API look & feel to the way we are actually constructing objects. Another thing to remember is that we are dealing with C#, and we have things like object initializers to do a lot of the heavy lifting for building objects. You should use that, for most cases.
NHibernate, for example, has the notion of a Builder, using the NHibernate.Cfg.Configuration object. It allows us to put all of the construction / validation code in one spot, and then the actual runtime code in a different place (and can assume a lot about its invariants). It also allows to do a lot of interesting things, like serializing the builder object (to save building time), which is something that you usually can’t / hard to do with real objects.
That said, you should be careful of code like the one listed above .What you have there is an overly abstract system. Requiring multiple steps to just get somewhere. If you find yourself feeding builders into builders, please stop and think about what you are doing. If you got there, you have not simplified the construction process.
Recommendation: This is still a very useful pattern. It should absolutely not be used if all you need to do is just setting some values. Reserve the Builder patterns where you actually have logic and behavior associated with the building process.
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 find this pattern priceless when working with legacy code.
I've been using message builders for a long time now and found they bring this to the table: - better semantics/intent (more verb-y than noun-y), - making a construct that is immutable, mutable for the duration of its construction, - allow different parts of the code to contribute to the building process
I agree with Ayende. In the real world what use a cook in a pizza parlour if he doesn't know how to make an Hawaiian pizza.
Yes, the example is too simplified and doesn't show real power of Builder pattern. It only shines when used in more complex scenarios or in conjunction with other patterns, like strategy. It is logical to use Builder when code specifying the construction details is actually different than the code that fetches the final result.
I like the Builder pattern as it is popular in the Java world: http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2
It allows you to create immutable objects without endlessly writing constructors for all cases. All checks can be conveniently put into the build() method.
If you don't mind creating a new builder every time you want to create a new object, there is a simpler way with almost no overhead compared to getters/setters: http://egalluzzo.blogspot.de/2010/06/using-inheritance-with-fluent.html
Or the fact that he's constructing it. Probably tastes like cardboard.
You can embed defaults in the builders instead of putting them in the objects you construct. That keeps your actual objects clean. Builders are priceless for building configuration too. Some examples are AutoFac's ContainerBuilder or the fluent config builders for EntLib. In these scenarios it makes a lot of sense to "feed builders into builders". Think of building a configuration for logging where you build the sub-config for formatting log entries and the like.
Comment preview