Fork me on GitHub

Factory Method

Motivation

Imagine that we need to develop a reporting library. Two basic abstractions in this library are the Engine and the Report classes. Both classes are abstract, and clients have to extend them in order to realize their application specific implementations.

The Engine class is responsible for managing Reports and will create them as required. Report subclasses which Engine should instantiate are application specific and Engine only knows when a new report should be created, but not what type of Report to create. This leads us to a situation in which our library should instantiate classes, but it only knows about abstract classes, which it cannot instantiate.

So, how can we solve this?

If we encapsulate the knowledge of which Report subclasses to create and move this knowledge outside of the library, then Engine subclass will be able to create Report objects. This solution is the Factory Method pattern.

The Factory Method defines an interface for creating objects, but lets subclasses decide which class to instantiate.

Story

Plasticine is used as a toy for children. Plasticine is injected into predefined molds. The class of end product (ball, toy, sculpture, cake) is determined by the mold.

Image

alt text

Cake molds, Han people, metal - Museum of Vietnamese History - Ho Chi Minh City, By Daderot (Own work) [CC0], via Wikimedia Commons

UML

Structure

The Product interface defines the interface of objects the factory method creates.
The ConcreteProduct class implements the Product interface.
The Creator abstract class declares the factory method interface.
The ConcreteCreator class implements the Creator’s factory method and returns an instance of the ConcreteProduct.

Implementation

Product.java

package com.hundredwordsgof.factorymethod;

/**
 * 
 * Product interface, defines the interface of the objects which factory method
 * creates.
 *
 */
public interface Product {

}

ConcreteProductA.java

package com.hundredwordsgof.factorymethod;

/**
 * 
 * ConcreteProductA class implements Product interface
 *
 */
public class ConcreteProductA implements Product {

}

ConcreteProductB.java

package com.hundredwordsgof.factorymethod;

/**
 * 
 * ConcreteProductB class implements Product interface
 *
 */
public class ConcreteProductB implements Product {

}

Creator.java

package com.hundredwordsgof.factorymethod;

/**
 * Creator class declares factory method
 */
abstract class Creator {

  abstract Product factoryMethod(String type);
}

ConcreteCreator.java

package com.hundredwordsgof.factorymethod;

/**
 * 
 * ConcreteCreator class returns an instance of the ConcreteProduct
 *
 */
public class ConcreteCreator extends Creator {

  public Product factoryMethod(String type) {

    if (type.equals("A")) {
      return new ConcreteProductA();
    } else if (type.equals("B")) {
      return new ConcreteProductB();
    }

    return null;
  }
}

Usage

FactoryMethodTest.java

package com.hundredwordsgof.factorymethod;

import static org.junit.Assert.assertEquals;
import org.junit.Test;

/**
 * Test implementation of the FactoryMethod pattern.
 */
public class FactoryMethodTest {

  @Test
  public void testFactoryMethod() {

    Creator factory = new ConcreteCreator();

    Product productA = factory.factoryMethod("A");
    Product productB = factory.factoryMethod("B");

    assertEquals("com.hundredwordsgof.factorymethod.ConcreteProductA",
        productA.getClass().getName());
    assertEquals("com.hundredwordsgof.factorymethod.ConcreteProductB",
        productB.getClass().getName());

    assertEquals(null, factory.factoryMethod(""));
  }
}