Contents
Introduction to the Factory Pattern
Design pattern in a simple meaning, is a way to design reusable object-oriented code. We can think of ways to design our classes, interfaces, enums and their members so that the code is reusable but flexible.
There are 23 most important design patterns, pioneered by the book Design Patterns: Elements of Reusable Object-Oriented Software, written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides or Gang of Four for short. We will cover these design pattern one by one.
The factory pattern is used when we have a base class and lots of subclasses and we have to create an object from the subclasses based on some conditions. By GoF definition, the pattern defines an interface for creating an object, but let the subclass of the class decide which to instantiate.
Implementation of the Factory Pattern
Say we have an Animal class with two subclasses Cat and Dog, the Animal.java:
public abstract class Animal { abstract void speak(); } class Dog extends Animal{ void speak() { System.out.println("growl"); } } class Cat extends Animal{ void speak() { System.out.println("meow"); } }
And the Factory.java:
public class Factory { public Factory(){} Animal createAnimal(String type){ Animal animal = null; if ("cat".equalsIgnoreCase(type)) animal = new Cat(); else if ("dog".equalsIgnoreCase(type)){ animal = new Dog(); } return animal; } }
So based on the String type passed to the createAnimal() method that the factory will create a Dog object or a Cat object. Finally in Test.java:
public class Test { public static void main(String[] args){ //create the factory Factory factory = new Factory(); //create Cat object Animal cat = factory.createAnimal("cat"); cat.speak(); //create Dog object Animal dog = factory.createAnimal("dog"); dog.speak(); } }
Run the code and we have the output:
meow growl
The Abstract Factory Design Pattern
The Abstract Factory is based on the Factory pattern, with one level higher of abstraction.
We will reuse the Animal.java from the previous example:
public abstract class Animal { abstract void speak(); } class Dog extends Animal{ void speak() { System.out.println("growl"); } } class Cat extends Animal{ void speak() { System.out.println("meow"); } }
Now we create a AnimalFactory interface in src folder, it is very simple:
public interface AnimalFactory { Animal createAnimal(); }
But instead of building a Factory class for both Dog and Cat classes, we create a Factory for each class. Also in the AnimalFactory.java:
class DogFactory implements AnimalFactory{ public Dog createAnimal() { return new Dog(); } } class CatFactory implements AnimalFactory{ public Cat createAnimal() { return new Cat(); } }
Finally we create a Factory class (also in AnimalFactory.java for simplicity) , this class will create the DogFactory and CatFactory based on the String type passed to it:
class Factory{ public AnimalFactory createFactory(String type){ AnimalFactory af = null; if ("cat".equalsIgnoreCase(type)) af = new CatFactory(); else if ("dog".equalsIgnoreCase(type)){ af = new DogFactory(); } return af; } }
This is the main difference between Abstract Factory pattern and Factory pattern. The Abstract Factory pattern creates a factory of other factories, not a factory of objects. Now in Test.java:
public class Test { public static void main(String[] args){ //create the abstract factory Factory fa = new Factory(); //create Cat factory AnimalFactory cFac = fa.createFactory("cat"); //create Cat object from factory Cat cat = (Cat) cFac.createAnimal(); cat.speak(); //create Dog factory AnimalFactory dFac = fa.createFactory("dog"); //create Dog object from factory Dog dog = (Dog) dFac.createAnimal(); dog.speak(); } }
Run the code and we have the output:
meow growl
As we can see, the Abstract Factory pattern is even better than the Factory pattern. Whenever we want to change something with each subclass, we will go to the subclass’s Factory and change it. The Abstract Factory and thus other subclass’s Factory will work as normal.
The Abstract Factory and thus other subclass’s Factory will work as normal.
We use the Abstract Factory when we needs to work with various families of related classes, but we don’t want it to depend on the concrete classes. They might be unknown until we create them, and we simply want to allow for future extensibility.