Factory Design Pattern

The Factory design pattern is mainly used when we have a class or interface with many subclasses or implementations, and according to some input, we need to return one of these specific subclasses.

When should we use a Factory class?

Let’s think of an interface from which we then make several implementations. We can use the typical Shape example interface from which we implement several classes like Circle, Rectangle, Square.

factory pattern

package patterns.factory;

public interface Shape {
    void draw();
}


package patterns.factory;

public class Circle implements Shape {

    @Override
    public void draw() {
        System.out.println("I am a Circle");
    }

}


package patterns.factory;

public class Rectangle implements Shape {

    @Override
    public void draw() {
        System.out.println("I am a Rectangle");
    }

}


package patterns.factory;

public class Square implements Shape {

    @Override
    public void draw() {
        System.out.println("I am a Square");
    }

}

In this case, we have several implementations and, depending on the type of Shape, we want to create the concrete implementation of the interface.

The usual way (without a factory) would be this way.


package patterns.factory;

public class FactoryPatternExample {

    public static void main(String[] args) {

        FactoryPatternExample example = new FactoryPatternExample();
        example.printShape("CIRCLE");

    }

    // Whithout factory
    public void printShape(String shapeType) {

        Shape shape;
        switch (shapeType) {
            case "CIRCLE":
                shape = new Circle();
                break;
            case "RECTANGLE":
                shape = new Rectangle();
                break;
            case "SQUARE":
                shape = new Square();
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + shapeType);
        }
        shape.draw();

    }

}

How to create a Factory class

We see in the previous example that we could simplify the creation of the class by taking everything in the switch to another Factory class that takes care of it, leaving our code simpler and clearer.

We are going to create a ShapeFactory class to resolve this:


package patterns.factory;

public class ShapeFactory {

    public static Shape getShape(String shapeType) {

        if (shapeType == null) {
            return null;
        }

        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        } else if (shapeType.equalsIgnoreCase("SQUARE")) {
            return new Square();
        } else {
            throw new IllegalStateException("Unexpected value: " + shapeType);
        }

    }

}

Let’s see what our previous example looks like using our Factory.

Note that it is much cleaner and clearer delegating the creation of the instances to the Factory.

The Factory will now be in charge of creating the particular instance, and our main class of example will make use of this factory forgetting the complexity to create it.

Java Factory Pattern

package patterns.factory;

public class FactoryPatternExample {

    public static void main(String[] args) {

        FactoryPatternExample example = new FactoryPatternExample();
        example.printShape("CIRCLE");

    }

    // Using Factory
    public void printShape(String shapeType) {

        Shape shape2 = ShapeFactory.getShape(shapeType);
        shape2.draw();

    }

}

Obviously this is a basic example, in general, the Factory class can be more complex taking care of creating instances under business conditions or various inputs that make their use convenient.

You can review this code GitHub

Hi! If you find my posts helpful, please support me by inviting me for a coffee :)

See also