Definition

The Factory pattern is one of the fundamental creational patterns along side the Singleton pattern which we talked about before.

The Factory pattern has the following responsibility according to the GoF's Book; Design Patterns: Elements of Reusable Object-Oriented Software.

Define an interface for creating an object, but let subclasses decide which class to instantiate.

What it's stating is that the Factory pattern takes care of creating objects without exposing the creation logic to the code that requires the object to be created.

Now the definition mentions exclusively that we define an interface. However, we don't have interfaces in JavaScript. Therefore, we are going to implement it in another way.

Note: This pattern could be found under the name of Simple Factory as well, which differ from the Factory Method and the Abstract Factory in the implementation, yet the concept is the same.

Examples

Let's start with a simple example that is well known when explaining this pattern.

function shapeFactory() {
    this.createShape = function (shapeType) {
        var shape;
 
        if (shapeType === 'rectangle') {
            shape = new Rectangle();
        } else if (shapeType === 'square') {
            shape = new Square();
        } else if (shapeType === 'triangle') {
            shape = new Triangle();
        } else if (shapeType === 'circle') {
            shape = new Circle();
        } else {
            shape = new Shape();
        }

        if (typeof shape.draw === 'undefined') {
            shape.draw = function () {
                // simple implementation
                console.log('This the default implementation, and the type is:', shapeType);
            }
        }
 
        return shape;
    }
}

var Shape = function () {};

var Rectangle = function () {
    this.draw = function () {
        console.log('This is a Rectangle');
    }
};
 
var Square = function () {
    this.draw = function () {
        console.log('This is a Square');
    }
};

var Triangle = function () {
    this.draw = function () {
        console.log('This is a Triangle');
    }
};

var Circle = function () {
    this.draw = function () {
        console.log('This is a Circle');
    }
};

var factory = new shapeFactory();

var rectangle = factory.createShape('rectangle');
var square = factory.createShape('square');
var triangle = factory.createShape('triangle');
var circle = factory.createShape('circle');
var hexagon = factory.createShape('hexagon');

rectangle.draw();
square.draw();
triangle.draw();
circle.draw();
hexagon.draw();

The shapeFactory constructor is responsible for creating new objects of the constructors Rectangle, Square, Triangle, and Circle. We created a method called draw which is implemented on each one of the previous shapes.

However, we defined a general Shape constructor that will take responsibility for dealing with a default shape that does not exist such as the hexagon object.

Every shape should define a draw method. However, if there wasn't one, the shapeFactory define it.

Addy Osmani's Learning JavaScript Design Patterns has a good example of the Factory pattern.

// Types.js - Constructors used behind the scenes
 
// A constructor for defining new cars
function Car( options ) {
 
  // some defaults
  this.doors = options.doors || 4;
  this.state = options.state || "brand new";
  this.color = options.color || "silver";
 
}
 
// A constructor for defining new trucks
function Truck( options){
 
  this.state = options.state || "used";
  this.wheelSize = options.wheelSize || "large";
  this.color = options.color || "blue";
}

// FactoryExample.js
 
// Define a skeleton vehicle factory
function VehicleFactory() {}
 
// Define the prototypes and utilities for this factory
 
// Our default vehicleClass is Car
VehicleFactory.prototype.vehicleClass = Car;
 
// Our Factory method for creating new Vehicle instances
VehicleFactory.prototype.createVehicle = function ( options ) {
 
  switch(options.vehicleType){
    case "car":
      this.vehicleClass = Car;
      break;
    case "truck":
      this.vehicleClass = Truck;
      break;
    //defaults to VehicleFactory.prototype.vehicleClass (Car)
  }
 
  return new this.vehicleClass( options );
 
};

// Create an instance of our factory that makes cars
var carFactory = new VehicleFactory();
var car = carFactory.createVehicle( {
            vehicleType: "car",
            color: "yellow",
            doors: 6 } );
 
// Test to confirm our car was created using the vehicleClass/prototype Car
 
// Outputs: true
console.log( car instanceof Car );
 
// Outputs: Car object of color "yellow", doors: 6 in a "brand new" state
console.log( car );