The builder pattern is appropriate when object creation is more complex than just calling a constructor. The factory pattern is appropriate when you have a hierarchy of created objects and you want to abstract the mapping of creation parameters to a subclass.
These patterns are often used together. Many abstract factories that I've written use builder functions. Sometimes I'll put the builder function into a base class -- which means that I have a builder function that is actually an abstract factory, which might itself use builder functions.
Now for more detail:
Builder
A Builder encapsulates complex creation into a single method (or class). If creating an object is more complex than just calling the constructor, then all of the work that goes into creating the object can be moved into one method, and that method is the Builder. 'Builder' implies only one type of created object, but that is not necessarily so. Builder really just means encapsulating complex construction!
Say that you want a Widget object, and that creating one means making a DB query or loading something from disk, constructing the object (passing in the query results), then making a few more calls to set up the object before it can be used.
Instead of copying and pasting that creation code -- query, construction, setup -- every time you need to create a Widget, you move all of that crap into a single function. The Widget constructor probably takes a whole bunch of parameters; maybe those come from the database query. Maybe the Widget uses multi-phase construction. The Builder pattern helps hide all that.
If the setup and configuration isn't really part of the created class, ie if it doesn't make sense for that class to know about all the other crap that needs to be done, the builder function might go somewhere else. I think 9 times out of 10 my builder functions are static methods in the created class itself. Instead of calling the constructor I call the builder function, and probably make the constructor private.
I usually use builder functions, not builder classes. The separate functions in a builder class might each return the same object just with different configurations, or each function might return different subclasses.
In languages where multi-phase construction is the norm (instantiate an object then make a bunch of function calls to fill it out), refactoring the construction steps into its own method is an instance of the Builder pattern!
Factory
A factory can create several different types of objects, but it returns its objects via an interface (or base class) reference. Whereas a Builder encapsulates complex construction steps, a Factory encapsulates the decision-making that figures out which specific subclass to instantiate.
Factories are accessed through a single method; that's really the point. You call one function, and it creates either a Subclass1 or a Subclass2, returning it via IBaseClass.
The Gang of Four book (Design Patterns) names both a Factory Method pattern and an Abstract Factory pattern.
In the Factory Method pattern, the factory function is virtual, and different subclasses of the creating class return different subclasses of the created class. That is, you call one class (the factory) to instantiate the second class (the created). The factory class is actually a tree - base class and subclasses. You'll have something like:
virtual ICreated* IBaseFactory::Create(...params...)So you have two class trees: the factories and the created objects. The two trees might be parallel, ie CFordFactory::CreateSedan returns an instance of CTaurus, and CNissanFactory returns CMaxima, etc etc. Or, the two trees might be disjoint: CFryingPan and CMicrowave return an instance of CFood, while CBlender returns an instance of CDrink (where both presumably derive from IConsumable).
You'll most likely use the Factory Method pattern when you have one hierarchy (the created objects), you're about to instantiate a whole bunch of objects, and you don't want to do a switch or if/else/else trees. So you move the creation into a new class tree, instantiate the factory subclass you want, and then use a method to create your objects.
Alternately, you might have a class that creates a bunch of objects, but that class is part of a hierarchy. Depending on which specific subclass you have, you'd get different created objects. That's the Factory Method pattern.
In the Abstract Factory pattern, you've actually got a set of factory methods. A food factory method, one for drinks, one for dishware, etc. More realistically, you might have a factory method for buttons, one for checkboxes, etc, where different factory subclasses create different appearances. In a game, you might have a barracks that will create an infantry, cavalry, and ranged unit, with different factories for each player race. Instead of disjoint classes for each type of unit, one class (IBarracks) will have three methods to create IInfantry, ICavalry, and IRanged units.
Besides subclassing, your abstract factory could be run off of some other logic. The factory function could do some magic to figure out which subclass to create. It could switch off of a parameter:
ICreated MyAbstractFactory.Create( Enum paramEnum )or it could use static data or other state to decide:
ICreated MyAbstractFactory.Create()Abstract Factory is a funky pattern. To use it, you'll want to be creating a matched set of objects. If you find yourself wanting to do that, Abstract Factory is your pattern.
see also
Bridge Pattern vs Strategy Pattern
Ownership, Aggregation, and Composition
1 comment:
Nice explanation. Best software development suggestion ever: "you move all of that crap into a single function." Inefficient code is crap until it's dealt with.
Post a Comment