In the last post of my creational design pattern series, I’ve described the singleton pattern:
Creational Design Pattern: Singleton
Singleton is one of the design patterns in the creational classification. This pattern lets you ensure that a class has only…
Now, let’s talk about the factory method pattern.
The factory method is a creational design pattern that provides an interface for creating an object in the superclass but allows subclasses to alter the type of object that will be created.
In a simple word,
A factory method is used to create multiple object types in a single interface.
Why use Factory Method?
As I said earlier, this pattern is used to create multiple object types in just a single interface. But what does it mean?. Before that, please take a look at the sample problem below.
Imagine that you’re creating a logistics management application. The first version of your app can only handle transportation by trucks, so the bulk of your code lives inside the Truck class.
After a while, your app becomes pretty popular. Each day you receive dozens of requests from sea transportation companies to incorporate sea logistics into the app.
Great news, right? But how about the code? At present, most of your code is coupled to the Truck class. Adding Ships into the app would require making changes to the entire codebase. Moreover, if later you decide to add another type of transportation to the app, you will probably need to make all of these changes again.
As a result, you will end up with pretty nasty code, riddled with conditionals that switch the app’s behavior depending on the class of transportation objects.
The factory method pattern suggests that you replace direct object construction calls (using the new operator) with calls to a special factory method. Don’t worry, the objects are still created via the new operator, but it’s being called from within the factory method. Objects returned by a factory method are often referred to as “products”.
At first glance, this change may look pointless: we just moved the constructor call from one part of the program to another. However, consider this, now you can override the factory method in a subclass and change the class of products being created by the method.
There’s a slight limitation though, subclasses may return different types of products only if these products have a common base class or interface. Also, the factory method in the base class should have its return type declared as this interface.
For example, both Truck and Ship classes should implement the Transport interface, which declares a method called deliver(). Each class implements this method differently: trucks deliver cargo by land, ships deliver cargo by sea. The factory method in the RoadLogistics class returns Truck objects, whereas the factory method in the SeaLogistics class returns Ships.
The code that uses the factory method (often called the client code) doesn’t see a difference between the actual products returned by various subclasses. The client treats all the products as abstract Transport. The client knows that all transport objects are supposed to have the deliver() method, but exactly how it works isn’t important to the client.
In this structure diagram, we have a Creator class that has the main function createProduct() to create a product. ConcreteCreatorA and ConcreteCreatorB is the implementation of the Creator class.
This Creator class is needed to create some “product”. So we create the Product interface. You must add your needs to your product class to this interface. For example, if you want to create a Truck and Ship product class that has the same method called deliver(), you must add method deliver() to this Product interface.
The ConcreteProductA and ConcreteProductB is the implementation of the Product interface.
So, in this structure, we can say that ConcreteCreatorA will produce a ConcreteProductA, ConcreteCreatorB will produce a ConcreteProductB, and so on.
As you can see, it’s easy to add a new product and creator with the factory method pattern, without changing your codebase.
FYI, some programmers like to change the name of the “Creator” class to the “Factory“ class. The responsibility is still the same, to create a product, but only the name is changed. For example, if we named a ConcreteCreatorA, we can also change this name to ConcreteFactoryA.
It’s Coding Time!
Let’s try to implement the factory method pattern using Kotlin language. We will make the Logistic app in a factory method pattern based on the structure above.
First of all, we need to create an abstract Logistic (Creator) class.
In this Logistic class, we declare abstract function createTransport() that return Transport type. This function will be overridden by the subclass and used to create a product and then return in Transport type.
And then, we declare the deliver() method to start to deliver our Transport product (for example, if we have created a Truck product, we can start delivery when the client code calls this deliver() method).
We need to implement a SeaLogistic and RoadLogistic class that extends the Logistic abstract class.
In this SeaLogistic class, we need to override the createTransport() method to return the Ship object, because Ship will work only in the sea. Make sense right?
And in the RoadLogistic class, we need to override the createTransport() method to return the Truck object.
After that, let’s create our Transport interface.
This interface will act as a type and the method declaration of our product. Let’s make our product class that implements this Transport interface.
In Ship class, we override the deliver() method to simulate deliver this Ship object.
And in the Truck class, we override the deliver() method to simulate deliver this Truck object.
Our code’s ready. Let’s create a FactoryMethodTest class to test our code.
We’ll try to create Ship using SeaLogistic, Truck using RoadLogistic, and deliver it in 5 times. The following code will result in output:
Delivering Ship with id: Ship@2c7b84de
Delivering Ship with id: Ship@3fee733d
Delivering Ship with id: Ship@5acf9800
Delivering Ship with id: Ship@4617c264
Delivering Ship with id: Ship@36baf30c
Delivering Truck with id: Truck@7a81197d
Delivering Truck with id: Truck@5ca881b5
Delivering Truck with id: Truck@24d46ca6
Delivering Truck with id: Truck@4517d9a3
Delivering Truck with id: Truck@372f7a8d
Congrats!, you’ve already implemented the factory method pattern.
Now, maybe you wonder how to add a new type of logistic? let’s say we want to add an AirLogistic with the product Plane.
We just need to add the creator,
and the Product,
That’s it! now you can use
val logistic = AirLogistic()
to start to deliver our Plane to the customer! :)
“Oh I see.., But that’s code only produce 1 product per creator. How to add a new type of product?, maybe with this AirLogistic, we need to send a Helicopter to some island that doesn’t have an airport”
In this case, we need to implement a creator that can produce multiple types of products. I will explain to you how to do it in Part 2 of this post. This post will be too long if I explain it here XD.
After all of that theory and code practice, we can conclude that implementing a factory method is simple as:
- Make all products follow the same interface. This interface should declare methods that make sense in every product.
- Add an empty factory method inside the creator class. The return type of the method should match the common product interface.
- In the creator’s code find all references to product constructors. One by one, replace them with calls to the factory method while extracting the product creation code into the factory method.
- Now, create a set of creator subclasses for each type of product listed in the factory method. Override the factory method in the subclasses and extract the appropriate bits of construction code from the base method.
- If there are too many product types and it doesn’t make sense to create subclasses for all of them, you can reuse the control parameter from the base class in subclasses.
- If, after all of the extractions, the base factory method has become empty, you can make it abstract. If there’s something left, you can make it a default behavior of the method.
When to use Factory Method?
- Use the Factory Method when you don’t know beforehand the exact types and dependencies of the objects your code should work with.
- Use the Factory Method when you want to provide users of your library or framework with a way to extend its internal components.
- Use the Factory Method when you want to save system resources by reusing existing objects instead of rebuilding them each time.
- You avoid tight coupling between the creator and the concrete products.
- Single Responsibility Principle. You can move the product creation code into one place in the program, making the code easier to support.
- Open/Closed Principle. You can introduce new types of products into the program without breaking existing client code.
- The code may become more complicated since you need to introduce a lot of new subclasses to implement the pattern. The best-case scenario is when you’re introducing the pattern into an existing hierarchy of creator classes.
Relation with other patterns
- Many designs start by using Factory Method (less complicated and more customizable via subclasses) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, but more complicated).
- Abstract Factory classes are often based on a set of Factory Methods, but you can also use Prototype to compose the methods in these classes.
- You can use Factory Method along with Iterator to let collection subclasses return different types of iterators that are compatible with the collections.
- Prototype isn’t based on inheritance, so it doesn’t have its drawbacks. On the other hand, Prototype requires a complicated initialization of the cloned object. Factory Method is based on inheritance but doesn’t require an initialization step.
- Factory Method is a specialization of Template Method. At the same time, a Factory Method may serve as a step in a large Template Method.