Object Creation Patterns #1 : Factory beats Builder

LMAX Exchange

Well, really, this should be obvious. My mental image of factories is the Toyota plant; an efficient production line of high tech robots automatically executing specialized constructive tasks as part of a well honed process (perhaps with a nearby overseer sternly observing, making regular marks on some sort of handheld checklist device). Whereas my builder image is a bloke leering at young ladies from the safety of some dodgy looking scaffolding.

Ahem

Uh. Yeah. I actually wanted to talk about the Factory and Builder patterns. They’re inescapable in modern OO codebases. I want to talk about the right time to use both patterns. In this part, we will discuss why Factory ought to be the default, and Builder‘s niche is, well, a niche. Later posts will examine the niche further, and probably digress into wider object creational concerns.

A little discipline

Alright, alright. We should define these terms.

Factory

Given a class Foo, a given Factory is a one shot method to construct a Foo.

Rule of thumb

Once we have a Factory, we are precisely one method call away from having a Foo. Factory objects might contain some pre-bound dependencies of Foo that they can inject on invocation, but usually this has occurred long before the invoker came into being.

Side note – Factory methods, usually implemented as static functions on Foo definitely get pulled in by this definition. (Q: what about Foo‘s constructor? Is that a Factory too?)

Builder

Given the same class Foo, a Builder allows us to piece together the dependencies of Foo in its internal state until we are ready to construct our Foo by invoking the build method.

Rule of thumb

Once we have a Builder, we could be n + 1 calls away from having a Foo, where n is the number of constructor parameters Foo has.

A completely irrelevant equivalence

One can immediately see that one could generate a Factory for a given Builder usage. Somewhat more generally, any Factory could be replaced with some equivalent calls to a complete Builder for a given class.

Takeaway from this section: Builders are more ‘general’ than Factories.

Wait a minute. Are you going to argue for or against generality?

Yes. What we are really seeking here is the appropriate level of generality for the situation we are in.

Factories are low risk; one might say they have low entropy. All the arguments we need in order to create a new object are clearly listed, passing the wrong number and/or the wrong type of arguments and the compiler will (assuming null is verboten) let us know long before the missiles have launched.

Builders come at a far higher cost; just as their construction is at least two phase, their contract is split too, between compile and run time. N.B The cost goes up if the builder’s implementation uses mutable fields, as they commonly do!

We can know fairly well that each of our calls parametrizes some aspect of the object under construction correctly, but do we know if all the dependencies it needs to construct our object have been provided when we invoke build? The only time we find out is at runtime, which may be too late. Let’s examine Builder from three different perspectives.

Using a Builder

We should be sure to write a test for our particular construction. If our usage is based on values only known at runtime, that might be quite a few tests, and a bundle of validation logic for our inputs. Ouch.

Writing a Builder

We’ll have a lot of fun considering the possible default values for fields, writing the validate method, and putting together the documentation that gives our clients the faintest chance of not failing it. You know the sort of arduous fun I speak of here, I am sure.

Receiving ‘built’ objects

We will be fortunate if we can work out all the different species of object that might occur! We’re probably going to want to use a property based testing tool to attempt to cover the vast range of objects we might end up dealing with. If we’re really lucky, a kind person might have hidden the built value behind a well defined interface that we can test against instead. I don’t know about you, but I don’t tend to be that lucky.

Conclusion

One hopes the above example gives some weight to the message of this piece, i.e there must be a strong need for the sort of generality a builder provides given the costs that come along with it.

Coming up next time: some strong needs, and master builders versus cowboy builders

Any opinions, news, research, analyses, prices or other information ("information") contained on this Blog, constitutes marketing communication and it has not been prepared in accordance with legal requirements designed to promote the independence of investment research. Further, the information contained within this Blog does not contain (and should not be construed as containing) investment advice or an investment recommendation, or an offer of, or solicitation for, a transaction in any financial instrument. LMAX Group has not verified the accuracy or basis-in-fact of any claim or statement made by any third parties as comments for every Blog entry.

LMAX Group will not accept liability for any loss or damage, including without limitation to, any loss of profit, which may arise directly or indirectly from use of or reliance on such information. No representation or warranty is given as to the accuracy or completeness of the above information. While the produced information was obtained from sources deemed to be reliable, LMAX Group does not provide any guarantees about the reliability of such sources. Consequently any person acting on it does so entirely at his or her own risk. It is not a place to slander, use unacceptable language or to promote LMAX Group or any other FX and CFD provider and any such postings, excessive or unjust comments and attacks will not be allowed and will be removed from the site immediately.