Factory Method Pattern

Definition

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

In this post we will have a look at the Simple Factory that will lead us to the Factory Method Design Pattern. The extension of the Factory Method will lead us to the Abstract Factory Pattern which we will see in the later posts.

Introduction

The TelevisionManufacturer class is responsible for creating Televisions. There are different kinds of television based on the type like LED, LCD and Plasma. Here’s a first attempt at the implementation.

Simple Implementation

package com.javadevcentral.pattern.factory.simple;

import com.javadevcentral.pattern.factory.TelevisionType;
import com.javadevcentral.pattern.factory.televisions.LCDTelevision;
import com.javadevcentral.pattern.factory.televisions.LEDTelevision;
import com.javadevcentral.pattern.factory.televisions.PlasmaTelevision;
import com.javadevcentral.pattern.factory.televisions.Television;

public class TelevisionManufacturer {
    public Television manufactureTelevision(TelevisionType televisionType) {
        Television television;
        switch (televisionType) {
            case LED:
                television = new LEDTelevision();
                break;
            case LCD:
                television = new LCDTelevision();
                break;
            case PLASMA:
                television = new PlasmaTelevision();
                break;
            default:
                throw new RuntimeException("Unknown Television type " + televisionType);
        }
        television.checkQuality();
        television.box();
        return television;
    }
}
package com.javadevcentral.pattern.factory;

public enum TelevisionType {
    LED,
    LCD,
    PLASMA;
}

Let Television be a simple class with a set of properties and let LEDTelevision, LCDTelevision and PlasmaTelevision inherit the Television class.

After creating a television, the manufacturer does some operations like QA check and finally boxes it. At runtime, it creates a Television object based on the type of television that is needed. There are several problems with this:

  • When we have to add (or remove) a new Television type, this class has to be changed. This clearly violates the Open Closed Principle (OCP) principle which states that classes must be open for extension but closed for modifications.
  • Often, creating a Television object for a given type might be needed in several other places too. Reuse of this logic is not possible with this structure or implementation.
  • Creating concrete classes in this class ties this class with the implementation details.

To solve this, we look at the design principle ‘Encapsulate what varies’. It says – identify the aspects that vary and separate them from what stays the same (We applied this in the Strategy Pattern too).

Simple Factory

The part of the code that creates concrete Television objects is the part that varies. So, we encapsulate it into a new object – the SimpleTelevisionFactory. Whenever we need a new Television (in the TelevisionManufacturer), we just call the createTelevision method on the TelevisionFactory.

package com.javadevcentral.pattern.factory.simple;

import com.javadevcentral.pattern.factory.TelevisionType;
import com.javadevcentral.pattern.factory.televisions.LCDTelevision;
import com.javadevcentral.pattern.factory.televisions.LEDTelevision;
import com.javadevcentral.pattern.factory.televisions.PlasmaTelevision;
import com.javadevcentral.pattern.factory.televisions.Television;

public class SimpleTelevisionFactory {
    public Television createTelevision(TelevisionType televisionType) {
        Television television;
        switch (televisionType) {
            case LED:
                television = new LEDTelevision();
                break;
            case LCD:
                television = new LCDTelevision();
                break;
            case PLASMA:
                television = new PlasmaTelevision();
                break;
            default:
                throw new RuntimeException("Unknown Television type " + televisionType);
        }
        return television;
    }
}

In this way, our manufacturer client code is not tied to any concrete Television class (it depends on the Television abstraction). This also enables any other code to reuse the TelevisionFactory to create Television objects. This also makes maintenance easy as there is just one place to change (the TelevisionFactory) when the type of televisions to support changes in the future.

The TelevisionManufacturer code now becomes, 

package com.javadevcentral.pattern.factory.simple;

import com.javadevcentral.pattern.factory.TelevisionType;
import com.javadevcentral.pattern.factory.televisions.Television;

public class TelevisionManufacturer {
    private SimpleTelevisionFactory simpleTelevisionFactory;

    public TelevisionManufacturer(SimpleTelevisionFactory simpleTelevisionFactory) {
        this.simpleTelevisionFactory = simpleTelevisionFactory;
    }

    public Television manufactureTelevision(TelevisionType televisionType) {
        Television television = simpleTelevisionFactory.createTelevision(televisionType);
        television.checkQuality();
        television.box();
        return television;
    }
}

We pass the TelevisionManufacturer a reference to the SimpleTelevisionFactory which it uses to create Televisions.

What we have seen above is an implementation of the ‘Simple Factory’. It is not a design pattern but it is a programming idiom used often. Do not confuse Simple Factory with the Factory Method.

Structure

Simple Factory

Supporting multiple manufacturers

Now, we have a Television Manufacturer class that can manufacture top-notch televisions. It is not coupled to any kind of Television object. Now, we need to support different manufacturers for different brands of TVs say, Samsung, LG, Philips, etc. Each manufacturer builds its own classes of Televisions (Samsung LED, Samsung LCD, Philips LEG, Philips LCD etc.)

Multiple Simple Factories

One option is to extend the idea of Simple Factory by replacing the SimpleTelevisionFactory with different factories for each of the manufacturers. Then we can pass the appropriate reference to a factory to our main TelevisionManufacturer

SamsungTelevisionFactory samsungTelevisionFactory = new SamsungTelevisionFactory();
TelevisionManufacturer televisionManufacturer = new TelevisionManufacturer(samsungTelevisionFactory);
//Creates Samsung LED TV
televisionManufacturer.manufactureTelevision(TelevisionType.LED); 

PhilipsTelevisionFactory philipsTelevisionFactory = new PhilipsTelevisionFactory();
TelevisionManufacturer televisionManufacturer = new TelevisionManufacturer(philipsTelevisionFactory);
//Creates Philips LCD TV
televisionManufacturer.manufactureTelevision(TelevisionType.LCD); 

This would work fine. But what if each manufacturer did the QA check or the boxing differently? So, we need a framework that ties the TV manufacturer and the manufacturing together.

Factory Method

We will bring the createTelevision method into the TelevisionManufacturer class but as an abstract method. We will have subclasses (of TelevisionManufacturer) for the different manufacturers (SamsungManufacturer, PhilipsManufacturer etc). They will provide an implementation for the createTelevision and they will fully own the Television creation logic. Since the createTelevision method is now abstract the TelevisionManufacturer class will also be marked abstract.

package com.javadevcentral.pattern.factory.method;

import com.javadevcentral.pattern.factory.TelevisionType;
import com.javadevcentral.pattern.factory.televisions.Television;

public abstract class TelevisionManufacturer {
    public Television manufactureTelevision(TelevisionType televisionType) {
        Television television = createTelevision(televisionType);
        television.checkQuality();
        television.box();
        return television;
    }
    protected abstract Television createTelevision(TelevisionType televisionType);
}

From the TelevisionManufacturer standpoint, it just calls the createTelevision abstract method, and it gets back a Television object. It does not know what kind of television is being returned. It is solely decided by the choice of the subclass (manufacturer) we choose to manufacture from.

Let us take a look at the individual manufacturers.

package com.javadevcentral.pattern.factory.method;

import com.javadevcentral.pattern.factory.TelevisionType;
import com.javadevcentral.pattern.factory.televisions.SamsungLCDTelevision;
import com.javadevcentral.pattern.factory.televisions.SamsungLEDTelevision;
import com.javadevcentral.pattern.factory.televisions.SamsungPlasmaTelevision;
import com.javadevcentral.pattern.factory.televisions.Television;

public class SamsungTelevisionManufacturer extends TelevisionManufacturer {
    @Override
    protected Television createTelevision(TelevisionType televisionType) {
        Television television;
        switch (televisionType) {
            case LED:
                television = new SamsungLEDTelevision();
                break;
            case LCD:
                television = new SamsungLCDTelevision();
                break;
            case PLASMA:
                television = new SamsungPlasmaTelevision();
                break;
            default:
                throw new RuntimeException("Unknown Television type " + televisionType);
        }
        return television;
    }
}

Similarly a PhilipsTelevisionManufacturer will look the same way except that it will return PhilipsLEDTelevisionPhilipsLCDTelevision and PhilipsPlasmaTelevision.

The abstract method on the TelevisionManufacturer is called the factory method. It takes care of object creation and encapsulates it in the subclass.

For the sake of completeness, a Television class described so far might look like this (The exact details are not important here).

package com.javadevcentral.pattern.factory.televisions;

import java.util.List;

public class Television {
    private String model;
    private int warrantyInYears;
    private List<String> specialFeatures;

    public void checkQuality() {
        System.out.println("Checking the Quality of the TV");
    }

    public void box() {
        System.out.println("Packing the TV in a box");
    }
}

Structure

Factory Method Pattern

Participants

Product (Television)

  • Defines the interface of objects the factory method creates.

ConcreteProduct (SamsungLEDDocument)

  • Implements the Product interface.

Creator (TelevisionManufacturer)

  • Declares the factory method, which returns an object of type Product. It calls the factory method to create a Product object.

ConcreteCreator (SamsungTelevisionManufacturer)

  • Provides an implementations of the factory method to return an instance of a ConcreteProduct.

Other Forms of Factory Method

Default implementation of the factory method: In some cases, the Creator class can provide a default implementation of the factory method. In such cases, the Creator class can be marked non-abstract.

Non-parameterized factory method: The version of the factory method that we saw involves sending a parameter to the factory method using which the subclasses made some decision. This is called a parameterized factory method. There is also another version that does not have any parameters.

Factory Method – Pros

  • Less coupling: No need to couple the creator class with specific concrete (Product) classes. It does this by moving the concrete Product object creation to the subclasses.
  • SRP and OCP: With above, we also adhere to the Single Responsibility Principle (SRP) and the Open Closed Principle (OCP).
  • Provides a hook for subclasses: When the factory method provides a default implementation, the factory method effectively becomes a hook. The subclasses can override this method to return a more specific object when the default implementation does not apply. For others, the default implementation would be sufficient.
  • Provides a framework: It allows us to build a framework involving the object creation through subclass. Usually the factory method is called from one of the methods (sometimes marked as final) in the abstract creator. Once the object (product) is created and returned, it does some operations on it. Thus, this other method provides a framework whereas the subclass decide what product object to create. 

Factory Method – Cons

  • Need to subclass: We have to create a subclass to implement the abstract factory method just to create a product.

Design principles used

Conclusion

The Factory Method allows us to encapsulate the creation of concrete objects. This leads to less coupling, code reuse, and easier maintenance. The Abstract creator has an (abstract) factory method that acts as a hook for the subclasses to create concrete product objects. The Abstract Creator does know about the concrete products that are created. It is decided by our choice of the subclass to be used. Usually the other methods in the Abstract Creator operate on the product object returned by the factory method. 

References and Resources

  1. Head First Design Patterns: A Brain-Friendly Guide by Eric Freeman and Elisabeth Robson.
  2. Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.
  3. Why is the factory method design pattern more useful than having classes and calling them individually?

Leave a Reply