When programming in object-oriented languages, design patterns are usually used to structure the relationships between classes and objects. It is often used in refactoring.
If you ask ChatGPT, it will tell you:
Screenshot of chat with chatGPT
There are mainly three types of design patterns, including creational, structural, and behavioral patterns. Each type consists of many subtypes. Here we will talk about the factory method, and abstract factory under creational type.
1. Creational
If one only uses the basic ways to create objects, it could bring technique debts in the software design in the long term. Creational design patterns try to solve the potential problems by creating objects in a way suitable to the situation.
Creational design pattern contains mainly five methods, including the factory method pattern, abstract factory pattern, builder pattern, prototype pattern, and singleton pattern. There is also one pattern called simple factory pattern which is related to the factory method pattern and abstract factory pattern, but simpler.
1.1. Simple Factory Pattern
If you want to make a product, e.g. book, that expresses a story, and there are many stories. For example, Harry Potter has seven books and Iron Man only has one. If you create a class for each specific story, you may have to write some same code over and over again for all those classes as they are all the same kind of products (they may have similar production procedure).
Simple factory pattern can solve this by simply exact a common abstract base class for the same type of products (books):
1 | public abstract class Book |
And each specified product can implement it:
1 | class HarryPotter : Book |
Then it uses a static factory method to create different instances (specific products) out of this base class:
1 | public class SimpleBookFactory |
Finally, in the application, the method can be used as:
1 | public static void main(String[] args) |
Through the simple factory pattern, one doesn’t need to create instance of a class in the application, which lowers the coupling. However, every time there is a new story, the SimpleBookFactory.makeBook method needs to be changed, which we do not want (If we did anything wrong when changing this method, all instances cannot be created properly). To overcome this problem, factory method pattern was created.
1.2. Factory Method Pattern
To not change the existing instance creating code, one can define a factory interface which contains the methods to produce products. Each product has their own factory which implements the interface.
The UML class diagram for factory method pattern can be seen as below:
So in the previous example, we keep the product classes:
1 | public abstract class Book |
But instead of SimpleBookFactory, now we have:
1 | public interface IFactory |
In this case, when creating instances in the application, we can directly call from the implemented specific factories:
1 | public static void main(String[] args) |
With the factory method pattern, except that we do not need to create instances of the products (stories) in the application, we also do not need to change existing factory methods when adding new products. But it increases the number of classes, since for every new story, there are a new product class and its corresponding factory class.
What if there is a need for the book factory to also produce comic books of Harry Potter and Iron Man?
1.3. Abstract Factory Pattern
Abstract factory pattern is more complicated and not as widely used as the previous two. It can be seen as a factory of factories.
The UML class diagram for factory method pattern can be seen as below:
For the same example, we still keep the product classes:
1 | public abstract class Book |
And now we need to make comic books, too:
1 | public abstract class ComicBook |
For the factory classes, since there are two main categories i.e., book and comic book, we can define a factory for each story. Each factory is responsible for making both categories:
1 | public interface AbstractFactory |
Finally in the application, we can produce products based on story:
1 | public static void main(String[] args) |
The core idea of abstract factory pattern is that it performs one more abstraction on the factory classes, which decreases the number of factory classes. It is particularly helpful if there is a great demand in products. However, the limitation of this pattern is also obvious. If there is a need to make, for example audio books, the AbstractFactory interface and all its implementation classes need to be changed too.