This chapter covers the abstract factory pattern.
GoF Definition
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
Note
To better understand this pattern, I suggest that you start at Chapter 24 (simple factory pattern) and then cover Chapter 4 (factory method pattern). The simple factory pattern does not fall directly in the Gang of Four design patterns, so the discussion on that pattern is placed in Part II of this book.
Concept
This is basically a factory of factories that provides one level of higher abstraction than the factory method pattern. This pattern helps us to interchange specific implementations without changing the code that uses them, even at runtime.
This pattern provides a way to encapsulate a group of individual factories that have a common theme. Here a class does not create the objects directly; instead, it delegates the task to a factory object.
The simple factory method pattern creates a set of related objects. In a similar way, since an abstract factory is basically a factory of factories, it returns factories that create a set of related objects. (I discuss the differences in detail in the “Q&A Session” section.)
Real-World Example
Suppose that we are decorating our room with two different tables: one made of wood and one made of steel. For the wooden table, we need to visit to a carpenter, and for the other table, we need to go to a metal shop. Both are table factories, so based on our demand, we decide what kind of factory we need.
In this context, you may consider two different car manufacturing companies: Honda and Ford. Honda makes models, such as CR-V, Jazz, Brio, and so forth. Ford makes different models, such as Mustang, Figo, Aspire, and so forth. So, if you want to purchase a Jazz, you must visit a Honda showroom, but if you prefer a Figo, you go to a Ford showroom.
Computer-World Example
To understand this pattern, I’ll extend the requirement in the factory method pattern. In factory method pattern, we had two factories: one created dogs and the other created tigers. But now, you want to categorize dogs and tigers further. You may choose a domestic animal (dog or tiger) or a wild animal (dog or tiger) through these factories. To fulfil that demand, I introduce two concrete factories: WildAnimalFactory and PetAnimalFactory. The WildAnimalFactory is responsible for creating wild animals and the PetAnimalFactory is responsible for creating domestic animals, or pets.
Note
The newInstance() method of javax.xml.parsers.DocumentBuilderFactory is an example of the abstract factory pattern in JDK. The newInstance() method of javax.xml.transform.TransformerFactory is another such example in this context. If you are familiar with C#, you may notice that ADO.NET has already implemented similar concepts to establish a connection to a database.
Illustration
AnimalFactory: An interface that is treated as the abstract factory in the following implementation.
WildAnimalFactory: A concrete factory that implements AnimalFactory interface. It creates wild dogs and wild tigers.
PetAnimalFactory: Another concrete factory that implements the AnimalFactory interface. It creates pet dogs and pet tigers.
Tiger and Dog: Two interfaces that are treated as abstract products in this example.
PetTiger, PetDog, WildTiger, and WildDog: The concrete products in the following implementation.
Here the client code is looking for animals (dogs and tigers). A common usage of this pattern is seen when we compose classes using the concrete instances of the abstract factory. I have followed the same. Notice that the client class contains the composed implementation of AnimalFactory. You can explore the construction process of both pet and wild animals in the following implementation.
Class Diagram
Package Explorer View
Implementation
Output
Q&A Session
- 1.
I am seeing that both the dog and the tiger interfaces contain methods that have the same names (both interfaces contain the speak() and the preferredAction() methods . Is it mandatory?
No. You can use different names for your methods. Also, the number of methods can be different in these interfaces. But I covered a simple factory pattern and factory method pattern in this book. You may be interested in the similarities or the differences between them. So, I started with an example and keep modifying it. This is why I kept both the speak() and preferredAction() methods in this example. Notice that these methods are used in both the simple factory pattern (see Chapter 24) and the factory method pattern (see Chapter 4).
- 2.What are the challenges of using an abstract factory like this?
Any change in the abstract factory forces us to propagate the modification of the concrete factories. If you follow the design philosophy that says program to an interface, not to an implementation, you need to prepare for this. This is one of the key principles that developers always keep in mind. In most scenarios, developers do not want to change their abstract factories.
The overall architecture may look complex. Also, debugging becomes tricky in some scenarios.
- 3.
How can you distinguish a simple factory pattern from a factory method pattern or an abstract factory pattern?
I discussed the differences between a simple factory pattern and factory method pattern in the “Q&A Session” section of Chapter 4.
Let’s revise all three factories with the following diagrams.
Simple Factory Pattern Code Snippet
Factory Method Pattern Code Snippet
Abstract Factory Pattern Code Snippet
Conclusion
With simple factory, you can separate the code that varies from the rest of the code (basically, you decouple the client codes). This approach helps you easily manage your code. Another key advantage of this approach is that the client is unaware of how the objects are created. So, it promotes both security and abstraction. But it can violate the open-close principle.
You can overcome this drawback using the factory method pattern that allows subclasses to decide how the instantiation process is completed. In other words, you delegate the objects creation to the subclasses that implement the factory method to create objects.
The abstract factory is basically a factory of factories. It creates the family of related objects but it does not depend on the concrete classes.
I tried to maintain simple examples that were close to each other. The factory method promotes inheritance; their subclasses need to implement the factory method to create objects. The abstract factory pattern promotes object composition, where you compose classes using the concrete instances of an abstract factory.
- 4.
In all of these factory examples, you avoid the use of parameterized constructors. Was this intentional?
In many applications, you see the use of parameterised constructors; many experts prefer this approach. But my focus is purely on design, and so, I ignored the use of parameterised constructors. But if you are a fan of parameterized constructors, let’s modify the implementation slightly so that you can do the same for the remaining parts.
Modified Illustration
Let’s assume that you want your factories to initialize tigers with specified colors, and the client can choose these colors.
Let’s modify the following pieces of code (changes are shown in bold).