Abstract Factory Pattern Explained

Abstract factory pattern is yet another creational design pattern and is considered as another layer of abstraction over factory pattern. In this tutorial, we will expand the scope of car factory problem discussed in factory pattern. We will learn when to use factory pattern by expanding scope of car factory and then how abstract factory pattern solves the expanded scope.

Table of Contents

1. Design global car factory using abstract factory pattern
2. Abstract factory pattern based solution
3. Abstract factory pattern implementation
4. Summary

1. Design global car factory using abstract factory pattern

In “factory design pattern“, we discussed how to abstract the car making process for various car model types and their additional logic included in car making process. Now, imagine if our car maker decides to go global.

To support global operations, we will require to enhance the system to support different car making styles for different countries. For example, in some countries we see steering wheel on left side, and in some countries it is on right side. There can be many more such differences in different part of cars and their making processes.

To describable the abstract factory pattern, we will consider 3 kind of makes – the USA, Asia, and the default for all other countries. Supporting multiple locations will need critical design changes.

First of all, we need car factories in each location specified in the problem statement. i.e. USACarFactory, AsiaCarFactory and DefaultCarFactory. Now, our application should be smart enough to identify the location where is being used, so we should be able to use appropriate car factory without even knowing which car factory implementation will be used internally. This also saves us from someone calling the wrong factory for a particular location.

So basically, we need another layer of abstraction which will identify the location and internally use correct car factory implementation without even giving a single hint to the user. This is exactly the problem, which abstract factory pattern is used to solve.

2. Abstract factory pattern based solution

2.1. Package Diagram

Class diagram for participating classes in design of global car factory using abstract factory pattern.

abstract_fctory_package_diagram-9778485

2.2. Sequence Diagram

This diagram shows the interaction between classes and abstraction behind CarFactory factory class.

abstract_factory_sequence_diagram-9375997

Please note that I have designed the solution to completely hide the location detail with end user. So, I have not exposed any location specific factory directly.

In alternate solution, we can first get the location specific factory based on location argument and then use it’s buildCar() method on abstract reference to build the actual car instance.

3. Abstract factory pattern implementation

Java classes implementing abstract factory pattern for global car factory.

First, wee have to write all separate car factories for different locations. To support, location specific features, begin with modifying our Car.java class with another attribute – location.

public abstract class Car {

  public Car(CarType model, Location location){
    this.model = model;
    this.location = location;
  }

  protected abstract void construct();

  private CarType model = null;
  private Location location = null;

  //getters and setters

  @Override
  public String toString() {
    return "Model- "+model + " built in "+location;
  }
}

This adds extra work of creating another enum for storing different locations.

public enum Location {
  DEFAULT, USA, ASIA
}

All car types will also have additional location property. We are writing only for the luxury car. Same follows for small and sedan also.


public class LuxuryCar extends Car
{
  public LuxuryCar(Location location)
  {
    super(CarType.LUXURY, location);
    construct();
  }

  @Override
  protected void construct() {
    System.out.println("Building luxury car");
    //add accessories
  }
}

So far we have created basic classes. Now let’s have different car factories which is the core idea behind abstract factory pattern.

public class AsiaCarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.ASIA);
      break;

      case SEDAN:
      car = new SedanCar(Location.ASIA);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.ASIA);
      break;

      default:
      //throw some exception
      break;
    }
    return car;
  }
}
public class DefaultCarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.DEFAULT);
      break;

      case SEDAN:
      car = new SedanCar(Location.DEFAULT);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.DEFAULT);
      break;

      default:
      //throw some exception
      break;
    }
    return car;
  }
}
public class USACarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.USA);
      break;

      case SEDAN:
      car = new SedanCar(Location.USA);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.USA);
      break;

      default:
      //throw some exception
      break;
    }
  return car;
  }
}

Well, now we have all 3 different Car factories. Now, we have to abstract the way these factories are accessed.

public class CarFactory
{
  private CarFactory() {
    //Prevent instantiation
  }

  public static Car buildCar(CarType type)
  {
    Car car = null;
    Location location = Location.ASIA; //Read location property somewhere from configuration
    //Use location specific car factory
    switch(location)
    {
      case USA:
      	car = USACarFactory.buildCar(type);
      	break;
      case ASIA:
      	car = AsiaCarFactory.buildCar(type);
      	break;
      default:
      	car = DefaultCarFactory.buildCar(type);
    }
  return car;
  }
}

We are done with writing code. Now, let’s test the factories and cars.

public class TestFactoryPattern
{
  public static void main(String[] args)
  {
    System.out.println(CarFactory.buildCar(CarType.SMALL));
    System.out.println(CarFactory.buildCar(CarType.SEDAN));
    System.out.println(CarFactory.buildCar(CarType.LUXURY));
  }
}

Program output:

Output: (Default location is Asia)

Building small car
Model- SMALL built in ASIA

Building sedan car
Model- SEDAN built in ASIA

Building luxury car
Model- LUXURY built in ASIA

4. Summary

We already have seen the use case scenarios of Factory pattern so whenever you need another level of abstraction over a group of factories, you should consider using the abstract factory pattern. It is probably only difference between factory pattern vs abstract factory pattern.

You can already look deeper into different real time examples of abstract factory in JDK distribution:

There are other similar examples but the need is to have the feel of the abstract factory design pattern, which you must have got till now.

Happy Learning!!

References:

Abstract factory – Wikipedia

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

18 thoughts on “Abstract Factory Pattern Explained”

  1. As per Abstract Factory pattern , It provides an interface for creating families of related or dependent objects without specifying their concrete class. but here the factory is returning only Car type. I think this a Factory method pattern with multiple concrete factory.
    Reference: https://en.wikipedia.org/wiki/Abstract_factory_pattern

    Could anyone please explain which one is correct implementation and why?

    Reply
  2. Hi Lokesh,

    I just want to understand whether location should be part of “Car”?
    Car has nothing to do with location then why did you put location as part of Car?

    //Bhupesh

    Reply
    • Given that each car instance in this application is going to be strictly location specific, how would you determine the location attribute of a random car instance in runtime of application if it’s not tied to car instance itself.

      Reply
  3. CarFactory method needs to be modified every time for switch case , when a location gets added. How could we make it extensible without modification.

    Reply
  4. Hello Lokesh,
    Thank you for the great tutorial!
    but I have a question. Can we implement an interfaces instead of Abstract Car and Abstract Factory classes?

    Supun

    Reply
    • Hi Supun, In my view interfaces should be used for adding the behavior to classes only. Here, we are creating instances of Car only in different ways. I think that abstract class make more sense here.
      BUT, there is no such restriction from design pattern side, you are free to implement using interfaces as well if you find it more easy. It’s matter of choice only.

      Reply
  5. Hi Lokesh, Thank you for such nice and simple explanation. I have one question, for example I have two different factories one for fruit, one for Vegetable, question is how can I use abstract factory pattern here.

    Reply
    • Talking about myself, I do not see any value addition in making abstract factory for your particular case. Fruits and Vegetables are two different entities and there are many major differences between them. So making two separate factories; one for each, makes more sense to me.

      Also, factory (or abstract factory) pattern should be applied on objects which you can build in different ways; in other words; there can be different representations of a object which belong a common parent.

      Your question is very good but to me, it’s really doesn’t fit into context.

      Reply
  6. Thanks for the article.Its explained well using the example of car.Now I need a real time scenario where this pattern is used(like factory is used in SessionFactory in hibernate)

    Reply

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.