November 8, 2022
css - javascript - design patterns - web development - frontend
6 minutes

Creational Patterns from Design Patterns

The purpose of `Creational Patterns` is to provide creation tools that increase flexibility and avoid code repetition.

NOTE:

This content only introduces each type without going into the details of each one. And it is necessary to have a basic knowledge of object orientation with javascript to understand this content.

We have some types of this design pattern:

Constructor Pattern

It consists of creating a class that has some parameters to define what will be the attributes of this creation.

For example a car, we could pass doors, engine and color, when we use this class, we pass these characteristics of our car to be able to be using it inside the class or return something.

class Car {
    constructor(doors, engine, color) {
        this.doors = doors
        this.engine = engine
        this.color = color
    }
}

We can be using a class that complements the other, for example. We have an SUV that contains 1 more attribute being wheels and the other attributes are the same as Car, so we simply call Car and add this wheels attribute in SUV so we don't repeat unnecessary code.

class Car {
    constructor(doors, engine, color) {
        this.doors = doors
        this.engine = engine
        this.color = color
    }
}

class SUV extends Car {
    constructor(doors, engine, color) {
        super(doors, engine, color)
        this.wheels = 4
    }
}

// CX5 contains 4 doors, V8 and reed color
const cx5 = new SUV(4, 'V8', 'red')

Singleton Pattern

The idea of this type of design pattern is to have a single class that is only defined initially and cannot be using this class for different results, see as an example:

let instance = null

class Car {
    constructor(doors, engine, color) {
        if (!instance) {
            this.doors = doors
            this.engine = engine
            this.color = color
            instance = this
        } else {
            return instance
        }
    }
}

// Civic contains 2 doors, V6 and grey color
const civic = new Car(2, 'V6', 'grey')

// Honda contains 2 doors, V6 engine and grey color (Equals Civic)
const honda = new Car(4, 'V8', 'red')

Basically it works by creating an instance when it is called the first time, and this value is stored in a variable, if it is called again it will use that same instance instead of recreating it and thus avoid repeated processing for cases where you need equal classes.

Factory Pattern

As the name says, this consists of being a factory of something, continuing the example of cars, we have several types of cars that we can be using in our code. So depending on the type of car that we pass to our factory, it should return the settings for that type of car, in the code it would look like this:

class Car {
    constructor(doors, engine, color) {
        this.doors = doors
        this.engine = engine
        this.color = color
    }
}

class Factory {
    createCar(type) {
        switch (type) {
            case 'civic':
                return new Car(4, 'V6', 'grey')
            case 'honda':
                return new Car(2, 'V8', 'red')
        }
    }
}

const factory = new Factory()

const myHonda = factory.createCar('honda')
const myCivic = factory.createCar('civic')

That way it's simple to get the information from the civic and honda for example.

Abstract Factory Pattern

It consists of having factory of factories, this is quite useful for larger applications where we can have several attributes but still we want to keep the get of this information simple.

Continuing with the example of cars, pretend that in addition to types, we have the model of the car, so according to the type of car, we call a specific factory for that type of car, passing the model as an attribute/parameter.

See how it would look in this example:

class Car {
    constructor(doors, engine, color) {
        this.doors = doors
        this.engine = engine
        this.color = color
    }
}

class carFactory {
    createCar(type) {
        switch (type) {
            case 'civic':
                return new Car(4, 'V6', 'grey')
            case 'honda':
                return new Car(2, 'V8', 'red')
        }
    }
}

class suvFactory {
    createCar(type) {
        switch (type) {
            case 'crv':
                return new Car(2, 'V8', 'black')
            case 'cx5':
                return new Car(4, 'V9', 'white')
        }
    }
}

const factoryOfCars = new carFactory()
const factorOfSUV = new suvFactory()

const autoManufacturer = (type, model) => {
    switch (type) {
        case 'car':
            return factoryOfCars.createCar(model)
        case 'suv':
            return factorOfSUV.createCar(model)
    }
}
// 4 doors, V9 engine and white color
const myCX5 = autoManufacturer('suv', 'cx5')

// 4 doors, V6 engine and grey color
const myCivic = autoManufacturer('car','civic')

We have these types of Creational patterns, I may be forgetting some here or I still don't know them, but I (Everton) know these.

It is necessary to analyze each case to define which pattern to follow, and the greatest knowledge about this comes with practice!

Thanks for reading this far, until next time.