Factory Method & Abstract Factory

Part 1: Factory Method

1. Definition

Definition in Wikipedia is:

It is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creaing objects by callying a factory method - either specified in an in interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes - rather than by calling a constructor.

So, the Factory Method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. This design pattern let factory defer subclass to decide instantiation.

2. Where we need factory pattern?

We want to use factory method to help us instantiate objects and encounter the following senerios.

  • The instantiation is complex.
  • Polymorphism. We don’t know which one to instantiate, we want to use some logic to decide which one to instantiate. There are two cases.
    • Objects are created in different ways.
    • Factory create different things.

Therefore, the Factory Method pattern solves problem like:

  • How can an object be created so that subclasses can redefine which class to instantiate?
  • How can a class defer instantiation to subclasses?

Creating an object directly within the class that requires (uses) the objects is inflexible because it commits the class to a particular object and makes it impossible to change the instantiation independently from (without having to change) the class. The Factory Method design pattern describes how to solve such problem:

  • Define a seperate operation (factory method) for creating an object.
  • Create an object by calling a factory method. This enables writing of subclasses to change the way an object is created (to redefine which class to instantiate).

3. UML

The UML is shown as follows.

In the above UML, the Creator class that requires a Product object doesn’t instantiate the ConcreteProduct class directly. Instead, the Creator refers to a separate factoryMethod() to create a proudce object, which makes the Creator independent of which concrete class is instantiated. Subclasses of Creator can redefine which class to instantiate.

Example

This example is from Wikipedia, click here to check.

A maze game may be played in two modes, one with regular rooms that are only connected with adjacent rooms, and one with magic rooms that allow players to be transported at random.

  • Room is the base class for a final product (MagicRoom or OrdinaryRoom).
  • MazeGame declares the abstract factory method to produce such a base product. MagicMazeGame and OrdinaryMazeGame are subclasses of MazeGame implementing the factory method producing the final produces.

Thus factory methods decouple callers(MazeGame) from the implementation of the concrete classes. This makes the “new” Operator redundant, allows adherence to the Open/closed principle and makes the final product more flexible in the event of change.

CLICK HERE TO SEE THE CODES
public abstract class Room {
  abstract void connect(Room room);
}

public class MagicRoom extends Room {
  public void connect(Room room) {}
}

public class OrdinaryRoom extends Room {
  public void connect(Room room) {}
}

public abstract class MazeGame {
  private final List<Room> rooms = new ArrayList<>();

  public MazeGame() {
    Room room1 = makeRoom();
    Room room2 = makeRoom();
    room1.connect(room2);
    rooms.add(room1);
    rooms.add(room2);
  }

  abstract protected Room makeRoom();
}

public class MagicMazeGame extends MazeGame {
  @Override
  protected Room makeRoom() {
    return new MagicRoom(); 
  }
}

public class OrdinaryMazeGame extends MazeGame {
  @Override
  protected Room makeRoom() {
    return new OrdinaryRoom(); 
  }
}

MazeGame ordinaryGame = new OrdinaryMazeGame();
MazeGame magicGame = new MagicMazeGame();

Part 2: Abstract Factory

1. Definition

Abstract Factory pattern provide an interface for creating families of related or dependent object without specifying their concrete classes. Difference between Factory Method is factory method create single object, abstract factory creates multiple objects.

2. What does abstract factor solve?

The Abstract Factory design pattern solves problems like:

  • How can an application be independent of how its objects are created?
  • How can a class be independent of how the objects it requires are created?
  • How can families of related or dependent objects be created?

3. UML

Image source: wikipedia

The Client class that requires ProductA and ProductB objects doesn’t not instantiate the ProductA1 and ProductB1 classes directly. Instead, the Client refers to the AbstractFactory interface for creating objects, which makes the Client independent of how the objects are created. The Factory1 class implements the AbstractFactory interface by instantiating the ProductA1 and ProdctB1.
The UML sequence diagram shows the run-time interactions: The Client object calls createProductA() on the Factory1 object, which creates and returns a ProductA1 object. Thereafter, the Client calls createProductB() on Factory1, which creates and returns a ProductB1 object.

4. Example

A classic application of abstract factory is the GUIFactory, say we want to design UI elements for different system. The UML is shown as follows. Image source: wikipedia

CLICK HERE TO SEE THE CODES
import java.util.List;
import java.util.Random;

// an existing hierarchy
interface Button {
  void paint();
}
class WinButton implements Button {
  @Override
  public void paint() {
    System.out.println("WinButton");
  }
}
class OSXButton implements Button {
  @Override
  public void paint() {
    System.out.println("OSXButton");
  }
}

public class AbstractFactoryExample {
  // abstract the way to create a button
  @FunctionalInterface
  interface GUIFactory {
    public Button createButton();
  }
  
  private static GUIFactory factory(String appearance) {
    switch(appearance) {
      case "osx":
        return OSXButton::new;
      case "win":
        return WinButton::new;
      default:
        throw new IllegalArgumentException("unknown " + appearance);
      }
  }
 
  public static void main(final String[] arguments) {
  // This is just for the sake of testing this program,
  // and doesn't have to do with the Abstract Factory pattern.
  var randomAppearance = List.of("osx", "win").get(new Random().nextInt(2));
    
  // get the button factory for an appearance
  var factory = factory(randomAppearance);
    
  // use the factory to create the button
  var button = factory.createButton();
  button.paint();
  } 
}

   Reprint policy


《Factory Method & Abstract Factory》 by Tong Shi is licensed under a Creative Commons Attribution 4.0 International License
 Previous
Valid Square Valid Square
LeetCode Q 593 - Valid SquareGiven the coordinates of four points in 2D space, return whether the four points could cons
2019-06-20 Tong Shi
Next 
Add Binary Add Binary
LeetCode Q 67 - Add BinaryGiven two binary strings, return their sum (also a binary string). The input strings are both
2019-06-19 Tong Shi
  TOC