An Abstract Factory provides an interface for creating families of related or dependent objects without specifying their concrete classes.

Why It’s Useful

Before we get into the dry definition of the Abstract Factory Pattern, let’s investigate a scenario where it would be useful. When we are going through this situation and solution, we will be using JavaScript – specifically ES6 to make our classes more readable.

Imagine we want to draw some shapes to an HTML5 Canvas. We’ll want to draw some common shapes like a Circle and a Square to the canvas, but we don’t want to bind our main code to the classes for a Circle and a Square. What we would like to do is have another class that knows how to make our shapes.

Some Code

Let’s write some simple code that models this situation. We’ll keep our implementation simple so that we can focus on the Abstract Factory Pattern instead of how Circles and Squares get drawn onto a canvas.

The HTML code:

<canvas id="canvas" width="500px" height="500px"></canvas>

This CSS code:

canvas {
  background-color: white;
  border: 1px solid black;
}

The JavaScript code (the important stuff):

class Shape {
  constructor(ctx) { this.ctx = ctx; }
  draw() { throw new Expection("Not implemented"); }
}

class Circle extends Shape {
  draw() {
    this.ctx.beginPath();
    this.ctx.arc(100, 75, 50, 0, 2*Math.PI);
    this.ctx.stroke();
  }
}

class Square extends Shape {
  draw() {
  	this.ctx.rect(20,20,100,100);
    this.ctx.stroke();
  }
}

class ShapeFactory {
  getShape(type, ctx) {
    switch(type) {
    case "Circle":
      return new Circle(ctx);
    case "Square":
      return new Square(ctx);
    default:
      throw new Exception("Type not found");
    }
  }
}

// Imagine this is in another file, that has no access to Shape, Square, or Circle,
// but does have access to ShapeFactory
const c = document.getElementById("canvas");
const ctx = c.getContext("2d");

const sf = new ShapeFactory();
const circle = sf.getShape("Circle", ctx);
const square = sf.getShape("Square", ctx);
circle.draw();
square.draw();



A runnable JSFiddle for you to preview the results:

The Pattern

In the previous code, we used a ShapeFactory to create objects of type Shape. Our main code was thus decoupled from the implementation details of a Circle or a Square. Our main code didn’t need to know how to make a Circle or a Square, it only needed to know about the ShapeFactory.

Generalizing this, the abstract factory pattern provides a way to create objects of a common theme by grouping individual factories together. When using the factory, your code doesn’t have to know which concrete object actually gets created by the internal factories. It only ends up using the generic interface of the theme.


This is part of our programming patterns series!

Learn more about design patterns with Design Patterns: Elements of Reusable Object-Oriented Software: