Creational Design Pattern: Factory

The Factory pattern is the second most commonly used design pattern. It is based on the idea that we can create objects of a common super type, while allowing their actual implementations to differ in subsequent subclasses.

The Factory pattern is the second most commonly used design pattern.

It is based on the idea that we can create objects of a common super type, while allowing their actual implementations to differ in subsequent subclasses.

This article is part of a series exploring design patterns using the Java programming language. The goal of this series is to help readers develop a solid understanding of design patterns while also sharing real-world examples from actual codebases that make use of these patterns.

In this article, we’ll be discussing the Prototype pattern.

Symbols for better navigation:

🤔 Hypothetical Scenario/Imagination

⚠️ Warning

👉 Point to note

📝 Common Understanding

Factory Design Pattern

👉 In other words, objects can share the same super type but still have different behaviors and properties depending on their subclass.

🤔 For example, let’s take a super interface IAnimal and two subtypes: ICat and IDog. Both ICat and IDog share the super type IAnimal, but their behavior and properties are clearly different.

Many times, the Factory Design Pattern is seen as the opposite of the Singleton Pattern. While the Singleton does not allow initialization with constructor parameters, the Factory pattern supports object creation with subtype-specific parameters.

Example Scenario

🤔 Imagine we are designing a Communication module in our hypothetical application.

Initially, customers can only reach our customer care executives through one medium i.e. Phone. So we design our app to support this communication channel.

Later, we introduce a website, and customers now want to contact us via Email as well. Soon, our VP announces that as the company grows, we will also need to support more communication channels like IMs and Social Media.

⚠️ This raises a concern: “How many more mediums will we need to add? And can we write our code in such a way that adding new mediums is simple and doesn’t break existing functionality?”

This is the exact scenario where the Factory Design Pattern comes to the rescue.

Applying Factory Design Pattern

📝 Instead of defining individual concrete classes like Phone, Email, etc., directly in our client code, we first define a super interface that represents the common behavior across all communication mediums.

For example, both Phone and Email should support basic actions like send and receive. So we create a super interface with these two methods.

Now, if Phone and Email also have their own unique behaviors, we can create separate interfaces for them, extending the super interface.

But the real question is:
How do we actually create concrete classes like Phone and Email?

👉 The answer: we use a Factory.

The factory takes care of instantiating the correct concrete class. In essence, it is a factory that produces products.

Java
class TestFactoryPattern {
  public static void main(String[] args) {
    CommFactory factory = CommFactory.getInstance(); // factory
    IPhone phoneMedium = factory.createMedium(CommType.Phone);
    IEmail emailMedium = factory.createMedium(CommType.Email);
  }
}

Now, if a new demand comes in, for example, adding a new medium like SocialMedia—we can simply create a new interface and add it to our factory.

📝 Few things to note in factory pattern:

  1. Instantiation logic of concrete classes is hidden from the client.
  2. Properties are set by the user, not fixed at construction time.
  3. The factory’s create method can enforce contracts and provide default values while creating objects with parameterized inputs.
  4. Existence of a product interface (the common super type) is necessary.

Recipe to create a Factory Pattern

The central part of a factory design pattern is a factory class.

Let’s suppose we have multiple product classes that need to be created.

First, we will visualise our factory as follows.

Java
class Factory {
  public static IProduct getProduct(ProductType type) {
    switch (type) {
      case ProductType.Product1:
        return new Product1();
      case ProductType.Product2:
        return new Product2();
    }
    return null;
  }
}

Next, we will create a super interface for our products.

Java
interface IProduct {
  public String getProductName();
  public int getType();
}

Subsequently, we will also define interfaces for individual products.

Java
interface IProduct1 extends IProduct {
  public void do();
}

interface IProduct2 extends IProduct {
}

Finally, we will create our empty concrete classes.

Java
public class Product1 implements IProduct1 {
  public String getProductName() {
    return "Product 1";
  }
}

public class Product2 implements IProduct2 {
  public String getProductName() {
    return "Product 1";
  }
  
  public void do() {};
}

Now, as demonstrated above by the communication factory method, the usage of our product factory by the user will be as follows:

Java
public class Test {
  public static void main(String[] args) {
    IProduct prod1 = Factory.getProduct(ProductType.Product1);
    System.out.println(prod1.getProductName());
  }
}

Real World Use of Factory

The factory design pattern is heavily leveraged by the Eclipse framework and the Eclipse Modelling framework to deliver plugins and rich client applications.

A common example of the use of a factory in Eclipse IDE plugin development to create resources like XML files is as follows.

Java
final ResourceSet resourceSet = new ResourceSetImpl();
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xml", new XMIResourceFactoryImpl());
final Resource resource = resourceSet.createResource(URI.createURI("test.xml"));

For more information on usage of Eclipse Modelling framework checkout the EMF’s github repo containing examples.

Up Next in the Series

Structural Design Pattern: Adapter

Subscribe to my newsletter today!

Share it on

Leave a Reply

Your email address will not be published. Required fields are marked *