I know there are hundreds of articles available in the web on this topic but this is such an interesting design pattern that I decided to also write about it. It took a lot of search and deep understanding of the concepts of one of the most important design patterns, the Abstract Factory Pattern. I will try to explain it. At first, it may sound quite similar to the Factory Pattern, but they are not the same. The Abstract Factory Pattern is at one level above the Factory Pattern.
When I began to get an idea of this pattern, I persisted and continued to scratch my head for days, with many articles on the internet, but all of them had the same definition as in the following:
"Results in an interface that provides families of related or dependent objects without providing their concrete classes."
I was not able to figure out what exactly does families of related or dependent objects in the definition mean. Finally, I was able to figure out the understanding of this definition, by comparing some of the articles that provided good real-world examples and related their examples with my example from the real world. So the result I developed is explained in the examples below.
What is Abstract Factory Design Pattern?
According to GoF's definition, this pattern "Provides an interface for creating families of related or dependent objects without specifying their concrete classes".
This pattern is generally referred to as a super-set of the Factory Pattern.
Since it is a broader, or a super-set, of the Factory Pattern, we will try to explain this with an example of the Factory Pattern and try to move on to the Abstract factory. So let's start with the Factory Pattern example.
A real-world example for Factory Pattern
Suppose your company gets an assignment in .NET technologies. You have a team of 20 members in .NET, with one team of Silverlight and another of .Net. Your business development team says, provide us the team of members with a required skillset. So your manager receives the required skill set from the BD team, selects a team from the two and gives them the assignment. So here:
- BD team acts as the client who requests a team to work on a project.
- Your manager acts on the Factory, who will decide the team to be selected.
- Silverlight and .Net teams are one of the final outputs/resources received by the client or the BD team to work on the project.
So our factory structure will be something like the following:
And our BD team or client will be sending the request as:
Run the code and see the results.
So this was the Factory Pattern, where you have a single requirement (or a single product to be more precise, in terms of the definition of this pattern).
So now your company needs to receive a new project that requires two different teams, one of .NET and another of mobile technologies (could be Windows or could be Android based), to work on another project.
So here we have more options to do this requirement.
Option One
Add another method to the same factory we created above, to get the team for the mobile technologies. So our code becomes:
But this will not be a good approach. This is because we have added one more functionality; we should be making it more abstract, since we might get another project in the future, that may want to have its own criteria of selecting a team or that may add another requirement like a Java team to be included.
Option Two
We create another factory like the one we created for the .NET and then get the required team from the Mobile technologies team. But this is also not a good approach, since this may result in more and more factories as the requirements of adding more and more teams arises. Also for the same reason above, we may have more projects in the future, that may also need the selection of a mobile and .Net technology team to work on.
The concept that we have discussed until now provides us the following points:
- We may have more requirements in the future (in other words we may need a third type of team like Java or any other technology team), for other projects. So we may be required to create another factory and may increase in number, as more requirements are added.
- Right now, we have only one project and based on it we send the requirements and get the required output. But another project, may have different requirements. That project may have its own way of deciding the basic criteria for selecting the required team.
So, these are the two main points, that are addressed by the Abstract Factory Pattern. Let's see, how to do this technically in code and then we will discuss the preceding two points, handled by our code.
So our first job will be to create a Base Factory, that will be encapsulating the definition of the factories (or Team deciding factories).
Now comes the main point of explanation. We will be creating 2 different factories that will implementing the base factory, in their own ways . These factories are nothing but the Projects that we receive. So both of these projects will be deciding their requirements for getting the two different teams, in their own way. This is nothing but point 2 from above.
So our code becomes the following, for the two different projects. For project one:
For project two:
As we can see, we have no specific requirements for selecting the teams for project two. Both of these projects provide their own implementations.
Finally, further class implementations will remain the same like the following
:
Now the BD team will be getting the requirements as:
Now, run the code and see the results.
The following explains how the code above covers the two points that we covered earlier.
- For the first point we discussed above, since more technology teams are to be added, we have the same requirements being addressed by the use of a common base interface IBaseFactory. So we can add more teams whenever required, in the base factory (like we added the IMobileTechnologiesTeamFactory team).
- The second point we discussed was regarding different requirements of different projects. So class ProjectOne specifies its own requirements for the teams required and class ProjectTwo, does not have any specific requirements. So both have their own definitions.
These are, what I feel, are the reason for the use of this design pattern and what I understand about this pattern from my study. One last point, remember the definition that I mentioned in the start of the article:
"Results in an interface that provides families of related or dependent objects without providing their concrete classes."
This is also in sync with the example we discussed, since we have the interface IBaseFactory, with related groups of functionality in a single unit.
Any more suggestion/points you would like to add to this article are welcome.