Ah, object creation. Why must you be so problematic? Is it the way you inject dependencies on global classes into the most innocent of code? Or the way you tie us down to concrete implementations instead of beautifully abstract interfaces?
Object construction is too large a topic for one essay, so let's focus on one common case: constructing objects private to a class. Here, the object is constructed and used internally by one class and its subclasses. For example, consider a pop-up Window with a single 'Ok' Button on it. Here's the most 'obvious' way to construct the button (in psuedo-code):
PopUp extends Window:
# PopUp is the constructor
method PopUp():
this.okButton = new Button('Ok')
this.okButton.onClick( this.close )
# do a bunch of other setup
...
Here we construct the button in the constructor. This is reasonable... as long you never want anyone to extend or modify the class. They could override the constructor to use a different button, but there's no way to prevent the construction of the original button. (In some languages, sub-classes don't technically have to call into the superclass constructor, but in practice it's almost always necessary.) This violates the open/closed principle and common sense; not everyone is going to want to use our specific Button implementation.
Getting Construction out of the Constructor
That's easy enough to fix, though: just move that part of the constructor to a separate method. That will enable that one aspect of the constructor to be overridden separately.
PopUp extends Window:
method PopUp():
this.initOkButton()
# do a bunch of other setup
...
method initOkButton():
this.okButton = new Button('Ok')
this.okButton.onClick( this.close )
It also improves the style, since we've split an atomic unit of work off into a single method.
Functions should be short and sweet, and do just one thing. - Linux Coding Style
Using a Factory Method
That was a good first step, but it's far from perfect. Take a look at the signature of the initOkButton()
method; it accepts no parameters, and returns nothing. There's no mention of Button
at all! Instead, the method is expected to install the button into a known member as a side effect. That's harder to document, and isn't enforced in any way. In C++ and Java it also requires the okButton
member to be either protected or public when it really should be private. We can fix all these problems by writing the method so that it returns the newly constructed button:
PopUp extends Window:
method PopUp():
this.okButton = this.newOkButton()
this.okButton.onClick(this.close)
# do a bunch of other setup
...
method newOkButton() returns Button:
return new Button('Ok')
This is called the Factory Method pattern. Notice how hard it is to mess up: you have to return a Button, so you pretty much have to create one. Also, the okButton
member can be private if it needs to be; the factory method doesn't access it directly. I've also moved some of the setup (registering the click listener) out of the factory method. That's because every ok button will need that listener registered, and shared behavior should be moved to the base class. If that step was left in the factory method, it would be just one more thing for the implementor of the subclass to mess up. In another situation, I might have granted subclasses more freedom and responsibility by placing the setup code in the factory method.
You can see the Factory Method pattern as a special case of the Template Method pattern: newOkButton()
defines how to create the ok button, but the base class decided if and when to call it.
I like to give factory methods the "new" prefix since they're used exactly like a constructor with the new
operator. The verb "create" is another common prefix for factory methods, as seen in the W3C DOM standard, Java's Abstract Window Toolkit, etc.
Notice that this use of the Factory Method pattern is extremely simple; there is no dynamic switching between different implementation classes, for example. That's ok; subclasses may want to provide more complex implementations:
SuperPopUp extends PopUp:
method newOkButton() returns Button:
if (this.buttonIsSuperToo):
ok = new SuperButton('Ok')
else:
ok = new Button('Ok')
# make the button's hover behavior snazzy
ok.onMouseOver(this.highlight)
ok.onMouseOut(ok.unhighlight)
return ok
In C++, subclasses can override private methods even though they cannot call them. Java makes the opposite design decision and does not allow private methods to be overridden. In Java, factory methods should be protected, as you would not want this implementation detail to be part of the public interface. In C++, you have a legitimate choice between private and protected.
Getting Lazy: Delaying Construction
We've made a lot of progress by moving object construction to its own method. However, we still are using a member to store the object, and therefore need to initialize that member in the constructor to gaurentee that it's always defined. However, this isn't always the best approach. Real-world window classes, for example, often have a seperate method like show()
or render()
that is responsible for making the window visible. We don't actually need to construct the OK button until the window is rendered. In other examples, the factory method may never be called, or it may be unclear exactly when it will be first called.
We can solve these problems by pairing the factory method with an protected "getter" method that constructs the object as needed.
PopUp extends Window:
private Button okButton = null
method PopUp():
# do a bunch of other setup
...
protected method getOkButton() returns Button:
if ( this.okButton == null ):
this.okButton = this.newOkButton()
return this.okButton
method newOkButton() returns Button:
return new Button('Ok')
method show():
ok = this.okButton()
ok.onClick(this.close)
# other rendering code
...
Here, the only method that should ever access the okButton
member is getOkButton()
, so that member should be private. getOkButton()
is then the only way to access the button, so it should be protected, not private, so subclasses can access the button. In the example, the button is not created until the first time it is needed, at which time we let the newOkButton()
factory provide us with the correct button.
We could of course just provide a method like getOkButton()
and ask subclasses to duplicate the caching behavior it provides, but common behavior belongs in the base class, and at the end of the day, it's much harder to mess up overriding the newOkButton()
method. Remember, the getter method may be called multiple times throughout the rest of the class, and its important that it return a reference to the same object each time. For example, if we register the click listener on one button but rendered another, then clicking it would do nothing. Implementing the caching behavior in the base class as getter method enforces this behavior.
If you've paired a factory method with a getter, then the factory method should typically be private in C++. Only the base class getter should ever call it.
Multiple Construction
In the examples so far, we've only used the factory to construct a single object. But its natural, easy, and beneficial to write factories to support multiple object creation. For example, suppose we want our PopUp to have any number of buttons on it. We just write a more general button factory:
method newButton(text):
return new Button(text)
And this method could be overridden in the SuperPopUp like so:
method newButton(text):
if (this.buttonIsSuperToo):
ok = new SuperButton(text)
else:
ok = new Button(text)
# make the button's hover behavior snazzy
ok.onMouseOver(this.highlight)
ok.onMouseOut(ok.unhighlight)
return ok
In this case, using the factory method guarantees that all the buttons are the same kind. Or, we can use the arguments to decide which Button implementation to use:
method newButton(text):
if (text.length > 10):
return new WrappingButton(text)
else:
return new Button(text)
Note that any time we write a factory method, we're leaving it up to the base class as to how many times it gets called. So, even using this generic factory, we can still use a getter to lazily create the OK button specifically:
method getOkButton():
if ( this.okButton == null ):
this.okButton = this.newButton('Ok')
return 'Ok'
So there's no reason to write specific rather than generic factory methods. There's no limit to how generic a factory method can be made. For example, you can pass in arguments that are only meaningful for particular implementation, and let the factory method decide what to use for each construction:
method newButton(text, wrappingLength):
if (text.length > 10):
return new WrappingButton(text, wrappingLength)
else:
return new Button(text)
Recap
Direct object creation is always a risk to the re-usability of a class. Someone, somewhere, will need to use a different implementation (of the same interface) then the one you chose. Adhere to the open/closed principle and allow extensions to change which implementations are used, by always constructing objects in separate factory methods. It goes without saying that you will need to access the object through an abstract interface throughout the rest of the code for this to work. In some cases you can encapsulate object creation even farther, delaying it until necessary with a lazy getter method. In all cases, you should try to write generic factory methods that can be called zero, one, or several times. Factory methods for constructing private members should generally be protected, not public, although in C++ in is sometimes useful to make them private.
- Oran Looney October 12th 2008
Thanks for reading. This blog is in "archive" mode and comments and RSS feed are disabled. We appologize for the inconvenience.