Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

JavaScript Essentials - Design Patterns

Using design patterns in JavaScript

Design patterns are proven solutions to common problems in software design. This tutorial covers some of the most commonly used design patterns in JavaScript, including Singleton, Factory, Observer, and Module patterns.

Key Points:

  • Design patterns help create flexible, reusable, and maintainable code.
  • Understanding common design patterns can improve your problem-solving skills.
  • Applying the right design pattern can simplify complex code structures.

Singleton Pattern

The Singleton pattern ensures that a class has only one instance and provides a global point of access to it. This pattern is useful for managing global application states or single resources.


// Singleton Pattern
const Singleton = (function() {
    let instance;

    function createInstance() {
        const object = new Object('I am the instance');
        return object;
    }

    return {
        getInstance: function() {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // Output: true
                

Factory Pattern

The Factory pattern provides a way to create objects without specifying the exact class of the object that will be created. This pattern is useful for creating different types of objects based on some condition.


// Factory Pattern
class Car {
    constructor(make, model) {
        this.make = make;
        this.model = model;
    }
}

class Truck {
    constructor(make, model) {
        this.make = make;
        this.model = model;
    }
}

class VehicleFactory {
    createVehicle(type, make, model) {
        switch(type) {
            case 'car':
                return new Car(make, model);
            case 'truck':
                return new Truck(make, model);
            default:
                return null;
        }
    }
}

const factory = new VehicleFactory();
const myCar = factory.createVehicle('car', 'Toyota', 'Corolla');
const myTruck = factory.createVehicle('truck', 'Ford', 'F-150');

console.log(myCar); // Output: Car { make: 'Toyota', model: 'Corolla' }
console.log(myTruck); // Output: Truck { make: 'Ford', model: 'F-150' }
                

Observer Pattern

The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. This pattern is useful for implementing event handling systems.


// Observer Pattern
class Subject {
    constructor() {
        this.observers = [];
    }

    subscribe(observer) {
        this.observers.push(observer);
    }

    unsubscribe(observer) {
        this.observers = this.observers.filter(obs => obs !== observer);
    }

    notify(data) {
        this.observers.forEach(observer => observer.update(data));
    }
}

class Observer {
    constructor(name) {
        this.name = name;
    }

    update(data) {
        console.log(`${this.name} received data:`, data);
    }
}

const subject = new Subject();
const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');

subject.subscribe(observer1);
subject.subscribe(observer2);

subject.notify('Hello, Observers!');
// Output: Observer 1 received data: Hello, Observers!
// Output: Observer 2 received data: Hello, Observers!

subject.unsubscribe(observer1);
subject.notify('Another message');
// Output: Observer 2 received data: Another message
                

Module Pattern

The Module pattern is used to create a namespace for related functions and variables, providing a way to encapsulate and organize code. This pattern helps avoid polluting the global namespace and allows for private variables and functions.


// Module Pattern
const myModule = (function() {
    let privateVariable = 'I am private';

    function privateMethod() {
        console.log(privateVariable);
    }

    return {
        publicMethod: function() {
            privateMethod();
        }
    };
})();

myModule.publicMethod(); // Output: I am private
console.log(myModule.privateVariable); // Output: undefined
                

Summary

In this tutorial, you learned about using design patterns in JavaScript, including the Singleton, Factory, Observer, and Module patterns. Understanding and applying these design patterns can help you write more flexible, reusable, and maintainable code.