DEV Community

Cover image for Design Patterns in JavaScript
Sameer Srivastava
Sameer Srivastava

Posted on

Design Patterns in JavaScript

What is a Pattern?

A pattern can be thought of as a template, which can be used in few different situations. A pattern provides us with a solution strategy that we can apply to commonly occurring problems in software design.
Basically, design patterns allow the code you write to be easier to implement, build, and maintain.

Program to an interface, not an implementation.

Design Patterns Categories

Design patterns can be categorized into multiple categories. But following are used in general.

1) Creational Design Pattern
These mainly focuses on class instantiation or you can say handling object creation mechanism.
So these pattern help in solving issues that might generate by object creation. Factory, Constructor, Prototype, Abstract, Singleton, Builder are some of creational design patterns.

2) Structural Design Pattern
Structural design patterns are all about object composition. These mainly identify ways to realize the relationship between objects and ensure that one part of system is independent to another.
Decorator, Bridge, Flyweight, Adapter, Composite and Proxy are some of these patterns.

3) Behavioral Design Pattern
Behavioral design pattern focuses on object's communication in a system.
Some of these patterns are Iterator, State, Mediator and Observer.

JavaScript Design Patterns

There are numerous patterns which we could implement using JavaScript. But I'll be discussing on only four of them, namely Constructor Pattern, Module Pattern, Singleton Pattern and Prototype Pattern.

Constructor Pattern
We all know that constructors are used to initialize the object once the system allocates a memory to it. In JavaScript almost everything is an object, even functions.
Now JavaScript supports constructor functions and calling constructor function through "new" implies that we want that function to behave like a constructor and instantiate an object. Lets see it through an example:

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}
Person.prototype.fullName = function() {
  console.log(this.firstName + ' ' + this.lastName);
}
var driver = new Person('John', 'Doe');
driver.fullName();    //Prints John Doe in console

The above example demonstrates a simple constructor design pattern. Important thing to note here is that we are using function's prototype object to define fullName().
The reason behind this is that in this way the fullName() will not be redefined every time whenever we create new objects of Person. Now only a single instance of fullName() will be shared among different Person objects.

Module Pattern
Modules are small units of independent and reusable code. They help in keeping a section of code separate and organized. Modules helps in defining private and public members separately, making it one of the more desired design patterns in JavaScript paradigm.
With Module pattern we can mimic the concept of classes i.e. we include both private and public variables and methods inside a single object, also protecting pieces from leaking into global scope. So basically here we are encapsulating everything with the help of closures and exposing only public API. Take a look at the example below:

var counterApi = (function(){
  var counter = 0;

  var inc = function() {
    counter++;
  }

  var dec = function() {
    counter--;
  }
  return {
    increment: function() {
      inc();
    },
    decrement: function() {
      dec();
    },
    reset: function() {
      counter = 0;
    },
    getCounterValue: function() {
      return counter;
    }
  };
})();

counterApi.increment();
counterApi.increment();
counterApi.increment();
counterApi.decrement();
counterApi.reset();
console.log(counterApi.getCounterValue());

In the above example you can see that the variable counter is protected from the global scope thus behaving like a private member. The increment, decrement, reset and getCounterValue functions are exposed to the outer world and only these can access counter.
Within the Module pattern, variables or methods declared are only available inside the module itself (because of closure). Variables or methods defined within the returning object however are available to everyone.

Singleton Pattern
The singleton pattern restricts instantiation of a class to a single object. A new instance of class is created only when there is no instance in existence. However if an instance of a class exists, it is returned. Following is a simple example to implement this pattern:

var mySingleton = (function () {
  // Instance stores a reference to the Singleton
  var instance;
  function init() {
    // Singleton
    function printNum() {
      console.log(num);
    }
    var num = Math.random();
    return {
      printNumber: function() {
        printNum();
      },
      getNumber: function() {
        return num;
      }
    };
  };
  return {
    getInstance: function () {
      if (!instance) {
        instance = init();
      }
      return instance;
    }
  };
})();

var ins1 = mySingleton.getInstance();
var ins2 = mySingleton.getInstance();
console.log(ins1.getNumber() === ins2.getNumber()); // true

Prototype Pattern
Prototype pattern refers to creating objects based on the template of an existing one. In JavaScript, we can think this as a prototypal inheritance where the objects created act as prototypes for others.
The major advantage of prototype pattern is performance boost. All the child objects points to same function defined in parent object instead of creating their own copies.
We can make use Object.create() (it creates a new object, using an existing object as the prototype of the newly created object) to implement this pattern.

var libraryPrototype = {
  books: ['Book1', 'Book2'],
  getAllBooks: function() {
    console.log(this.books);
  }
}

var myLibrary = Object.create(libraryPrototype, 
{ 
  name: {
    writable: true,
    configurable: true,
    value: 'My Library'
  }
});

console.log(myLibrary.name); // prints "My Library"
myLibrary.getAllBooks(); // prints ["Book1", "Book2"]

So in the above example, libraryPrototype is existing object which acts as a prototype for myLibrary object. New properties to myLibrary can be initialized on the second argument of Object.create.

Design patterns can speed up the development process by providing tested, proven development paradigms.They are also quite a powerful approach to getting all of the developers in an organization or team on the same page when creating or maintaining solutions.
They are tools to improve efficiency but more importantly allow you as the developer to improve your overall design skills as well as the quality of your projects, and give you a wider scope of skill sets.

Top comments (0)