Abstract Factory Pattern

This lesson details the working of yet another creational design pattern, that allows us to create a family of products in a flexible and extensible manner.

What is it ?

In the previous lesson, we learned the factory method pattern. We saw how we were able to model the variants of the F-16 using the factory method. But there are numerous airplanes other than F-16 that we'll need to represent. Say the client buys a Boeing-747 for the CEO to travel and now wants your software to provide support for this new type of aircraft.

The abstract factory pattern solves the problem of creating families of related products. For instance, F-16 needs an engine, a cockpit, and wings. The Boeing-747 would require the same set of parts but they would be specific to Boeing. Any airplane would require these three related parts but the parts will be plane and vendor specific. Can you see a pattern emerge here? We need a framework for creating the related parts for each airplane, a family of parts for the F-16, a family of parts for the Boeing-747 so on and so forth.

Formally, the abstract factory pattern is defined as defining an interface to create families of related or dependent objects without specifying their concrete classes.

Class Diagram

The class diagram consists of the following entities

  • Abstract Factory
  • Concrete Factory
  • Abstract Product
  • Concrete Product
  • Client
Class Diagram
Class Diagram

Example

An abstract factory can be thought of as a super factor or a factory of factories. The pattern achieves the creation of a family of products without revealing concrete classes to the client. Let's consider an example. Say, you are creating a simulation software for the aviation industry and need to represent different aircraft as objects. But before you represent an aircraft, you also need to represent the different pieces of an aircraft as objects. For now let's pick three: the cockpit, the wings, and the engine. Now say the first aircraft you want to represent is the mighty F-16. You'll probably write three classes one for each piece specific to the F-16. In your code you'll likely consume the just created three classes as follows:

    public void main() {
        F16Cockpit f16Cockpit = new F16Cockpit();
        F16Engine f16Engine = new F16Engine();
        F16Wings f16Wings = new F16Wings();
    
        List<F16Engine> engines = new ArrayList<>();
        engines.add(f16Engine);
        for (F16Engine engine : engines) {
            engine.start();
        }
    }

This innocuous looking snippet can cause severe headaches down the road if your simulation software takes off and you need to expand it to other aircraft. Below is a list of what is wrong with the above snippet:

  • The concrete classes for the three parts have been directly exposed to the consumer.

  • F-16 has several variants with different engines and say in future if you want to return engine object matching to the variant, you'll need to subclass F16Engine class and that would necessitate a change in the consumer snippet too.

  • The List in the code snippet is parametrized with a concrete ...