JavaScript Design Patterns: Organize, Reuse, and Boost Your Code

Thea - Sep 11 '23 - - Dev Community

I recently started learning about design patterns and I was very impressed with how useful they are and how they can simplify software development.

Design patterns are solutions to common problems that are found in software. They are like recipes that you can follow to solve problems in an efficient way.

I think all front-end developers should learn about design patterns. They can help you write clearer, and easier-to-maintain code.

Let's explore five essential design patterns:

1.Module Pattern:
The module pattern allows encapsulating related functions and variables into a single object, making code more understandable and maintainable. It also helps protect sensitive data from unauthorized access.
Here's a simple example:

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

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

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

Module.publicMethod(); // Output: 'I am private'

Enter fullscreen mode Exit fullscreen mode

2.Observer Pattern:
The Observer pattern is a powerful tool that can be used to implement real-world scenarios (such as a notification system or a chat application) where one object needs to notify multiple other objects of changes to its state. It is a versatile pattern that can be used in a variety of different contexts.
Here's a basic implementation:

// Observer Pattern
function Subject() {
  this.observers = [];

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

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

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

function Observer() {
  this.update = function() {
    console.log('Subject has been updated!');
  };
}

const subject = new Subject();
const observer = new Observer();

subject.subscribe(observer);
subject.notify(); // Output: 'Subject has been updated!'
Enter fullscreen mode Exit fullscreen mode

3.Singleton Pattern:
The singleton pattern ensures that a class has only one instance and provides a global point of access to it. It is useful in scenarios where you need to restrict instantiation to a single object.
However, it is important to be aware of the potential drawbacks before using it, such as tight coupling and increased memory usage.
Here's a simple implementation:

// 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
Enter fullscreen mode Exit fullscreen mode

4.Decorator Pattern:
The Decorator pattern allows dynamically adding new behavior to an object by wrapping it with a decorator object. It provides flexibility to modify or extend the behavior of individual objects without affecting other instances of the same class.
Here's an example:

// Decorator pattern
function Coffee() {
  this.cost = function() {
    return 5;
  };
}

function CoffeeDecorator(coffee) {
  this.coffee = coffee;

  this.cost = function() {
    return this.coffee.cost() + 2;
  };
}

const coffee = new Coffee();
const decoratedCoffee = new CoffeeDecorator(coffee);

console.log(decoratedCoffee.cost()); // Output: 7
Enter fullscreen mode Exit fullscreen mode

5.Prototype Pattern
The Prototype pattern involves creating objects based on a prototype object and cloning them rather than creating new instances from scratch. It is useful for performance optimization and creating object hierarchies.
Here's a simple example:

// Prototype pattern
const carPrototype = {
  wheels: 4,
  start: function() {
    console.log('Car started');
  },
};

const myCar = Object.create(carPrototype);
console.log(myCar.wheels); // Output: 4
myCar.start(); // Output: 'Car started'
Enter fullscreen mode Exit fullscreen mode

Benefits and Best Practices

1.Benefits:

  • Code organization and maintainability
  • Code reusability and modularity
  • Scalability and flexibility
  • Improved collaboration among developers

2.Best Practices:

  • Choose the right design pattern for your problem domain.
  • Understand the pattern thoroughly before implementing it.
  • Keep your code modular and loosely coupled.
  • Document your design pattern implementation for future reference.

While there are many other design patterns in software development, this article focused on five essential patterns to provide a well-rounded introduction. As you progress in your journey, you can explore more advanced patterns to solve complex problems. Design patterns are powerful tools that simplify software development and promote best practices. Happy coding!

Additional Resources:

Design Patterns in JavaScript
Learning JavaScript Design Patterns by Addy Osmani

. . . . . . . . . . . . . . . . . . .