28 December 2018, 12:14

the factory pattern


Name: Factory

Type: Creational

Use when you want to:

  • Generate an instance for a client without exposing any instantiation logic to the client
  • Hide the dependencies of class instantiation from clients

Variants

Simple

From Wikipedia:

In object-oriented programming (OOP), a factory is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class from some method call, which is assumed to be "new".

Real World Example:

You are building a house that needs doors. You can either build the door from scratch, with all the things needed to do so (glue, tools, knowledge) or you can call the factory and have them build a door for you.

Main Purpose:

Simple factory simply generates an instance for client without exposing any instantiation logic to the client

Typescript Code Example:

Door interface and implementation

interface IDoor{
    getWidth: () => number;
    getHeight: () => number;
}

class WoodenDoor implements IDoor {
  constructor(public width: number, public height: number){
  }

  getWidth(): number{
    return this.width
  }

  getHeight(): number{
    return this.height
  }
}

Door Factory that makes an instance of the Door

class DoorFactory{
    public static makeDoor(w : number, h: number){ 
        return new WoodenDoor(w, h)
    }
}

And can be used like so:

const door = DoorFactory.makeDoor(100, 200)

console.log(door.getWidth())
console.log(door.getHeight())

const anotherDoor = DoorFactory.makeDoor(50,100)

Full example:

Method

This is a variation on the simple factory we looked at above. This method is used when there is some generic processing on a class but want to vary what kind of things the processing is done on.

From Wikipedia:

In class-based programming, the factory method pattern 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 creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.

Analogy:

Consider the case of a hiring manager. It is impossible for one person to interview for each of the positions. Based on the job opening, she has to decide and delegate the interview steps to different people.

Main purpose:

It provides a way to delegate the instantiation logic to child classes.

Typescript Code example:

Setup variations of question askers

interface IInterviewer{
    askQuestions: () => void;
}

class Developer implements IInterviewer {
  askQuestions() {
    console.log('Asking about design patterns!')
  }
}

class CommunityExecutive implements IInterviewer {
  askQuestions() {
    console.log('Asking about community building')
  }
}

Asking the question

abstract class HiringManager{

    // Factory method
    protected abstract makeInterviewer() : IInterviewer;

    public takeInterview(){
        const interviewer = this.makeInterviewer();
        interviewer.askQuestions();
    }
}

Who asks the question

class DevelopmentManager extends HiringManager {
    makeInterviewer() {
        return new Developer()
    }
}

class MarketingManager extends HiringManager {
    makeInterviewer() {
        return new CommunityExecutive()
    }
}

Usage

const devManager = new DevelopmentManager()
devManager.takeInterview() // Output: Asking about design patterns

const marketingManager = new MarketingManager()
marketingManager.takeInterview()// Output: Asking about community building 

Full Example:

Abstract

From Wikipedia:

The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes

Analogy:

Back to doors. Say this time we need a wooden door from a wood shop and a iron door from a iron shop. For each type of door you would need a different worker to create and fit the door.

Main Purpose:

A way to group individual but related/dependant factories together without specifying their concrete class

Door interface implementation

interface Door {
    getDescription() : void;
}

class WoodenDoor implements Door{
    public getDescription(){
        console.log('I am a wooden door');
    }
}

class IronDoor implements Door{
    public getDescription(){
        console.log('I am an iron door')
    }
}

Door Fitter and implemenation

interface DoorFittingExpert {
    getDescription() : void;
}

class Welder implements DoorFittingExpert{
    public getDescription(){
        console.log('I can only fit iron doors');
    }
}

class Carpenter implements DoorFittingExpert{
    public getDescription(){
        console.log('I can only fit wooden doors');
    }
}

Grouping the dependencies together

interface DoorFactory {
    makeDoor(): Door;
    makeFittingExpert(): DoorFittingExpert;
}

// Wooden factory to return carpenter and wooden door
class WoodenDoorFactory implements DoorFactory {
    public makeDoor(): Door {
        return new WoodenDoor();
    }

    public makeFittingExpert(): DoorFittingExpert{
        return new Carpenter();
    }
}

// Iron door factory to get iron door and the relevant fitting expert
class IronDoorFactory implements DoorFactory{
    public makeDoor(): Door {
        return new IronDoor();
    }

    public makeFittingExpert(): DoorFittingExpert{
        return new Welder();
    }
}

Usage

const woodenFactory = new WoodenDoorFactory()

const woodenDoor = woodenFactory.makeDoor()
const woodExpert = woodenFactory.makeFittingExpert()

woodenDoor.getDescription()  // Output: I am a wooden door
woodExpert.getDescription() // Output: I can only fit wooden doors

// Same for Iron Factory
const ironFactory = new IronDoorFactory()

const ironDoor = ironFactory.makeDoor()
const ironExpert = ironFactory.makeFittingExpert()

ironDoor.getDescription()  // Output: I am an iron door
ironExpert.getDescription() // Output: I can only fit iron doors

Full Example:

And that in a nutshell is the factory pattern!


← The Builder Pattern
Starting ~ 2019 →