Software Design Patterns: Factory and Builder in a Nutshell
A recurrent question that my students ask is about the difference, if any, between a Factory and a Builder, in terms of the software design patterns with these names. Moreover, they ask about the difference, if any, between the builder as described in the GoF patterns and the so-called Fluent-builder, commonly used in the Java Stream API when calling methods in the pipeline.
They are creational patterns, templates for object creation mechanisms suitable to a specific situation. The basic form of object creation (the new operator calling constructors) everywhere result in design problems and add complexity.
Remember, programming in the large is not the same that programming in the small: creating objects everywhere works for your school homework but it does not scale well. It is important to locate the object creation in one place as a responsibility of one entity or component, such as in a Factory or in a Builder. How to choose one or the other? What situation is suitable for each? Let talk about each of them, their similarities, and their differences.
A factory is an object for creating other objects. The Factory is a wrapper for a constructor, i.e., it is used to build one entire object in a single method call.
Two interfaces are defined to enforce properties: Factory and Product.
- The Factory interface defines the signature for the method to be called when a new object is needed. A factory can create one or more types of products. Therefore, it could have diverse methods, usually with a prefix create(), one per type of product, or uses parameters to specify what to construct. Factories implement this interface.
- The Product interface does not defines any specific content. It is to be customized acording to the problem being solved. Products implement this interface.
A class Client uses the Factory and gets a Product. Notice, how Client has dependencies with the interfaces Factory and Product, instead of with the concrete implementation of these interfaces. This is an open door for polymorphism — Client can work with any child (specialization) of Factory and Product.
For example, a software for drawing shapes, could use a factory (specifically a factory of shapes) able to create circles and rectangles. The design for that would be as shown in Figure 1. What about the code? Well, it is pretty straightforward from the class diagram. Let us see this from the top-down. Figures 2, 3, 4, and 5 show the source code for a class Client that uses the Factory to create Product objects, specifically Oval and Rectangle objects.
If you are familiar with the design pattern Singleton, think about the possibilities of combining and creating a Singleton-Factory, i.e., one single instance of Factory that could be called every time that a new object (product) is needed everywhere.
A Builder is a wrapper of an object. It is used when an object cannot be produced in one single step. Builder isolates the product’s internal representation and the steps for the product’s construction. Use the Builder pattern to get rid of having a Product with multiple constructors with a diverse number of parameters each, i.e., as an option for providing default values for attributes in an object.
The Builder creates a Product just as Factory did. But now, instead of only one request for creating the Product, there several calls to methods in the Builder. Each call adds a new part to the Product. When the Builder has been provided with everything needed, its method get() can be called to assemble the new Product with the elements that Builder received before.
Figure 6 shows the design for a BoxBuilder that builds Box objects. Figures 7, 8, and 9 show the source code for our new classes.
When obtaining the values for each attribute is a complex process, it is a good idea to add a class between Client and Builder, usually identified as a Director that could be the point of contact for Client and be responsible for creating, calculating or collect data (values for Product’s attributes). Director can have a Builder instance and delegate to it the assembly of the Product. The director calls the methods in Builder that constructs the Product step-by-step providing for each step the data needed.
The Fluent Builder is a builder whose design relies on method chaining. In doing so, it aims to promote code legibility. For example, the code in Figure 7 changes (to the one shown in Figure 10) when a Fluent Builder is used.
Notice how the methods in Line 6 to 9 are chained. What do we need to make that possible? A simple update in the Builder: replace the return type from void to Builder and make the methods return this (the current object). Therefore, in each call to a setter method, the Builder object is returned. The returned Builder object can call another setter method, and so on. The code to make that possible is as shown in Figures 11 and 12.
This is a very simple implementation, but it shows the idea.
If you are familiar with the Eclipse Modeling Framework, you will have noticed the extended use of Factory and Singleton Patterns. If you have read about Functional Programming in Java, I am confident that the Fluent-Builder seems familiar. And, if you have the opportunity to use Deep Learning Frameworks, such as DeepLearning4J, you had noticed the Fluent-Builder when creating neural networks.