Design Patterns in Javascript /Node — 2020

Shivam Gupta
8 min readMay 10, 2020

--

In this article, we are going to talk about design patterns that can be and should be used to write better, maintainable JavaScript code

A design pattern provides a general reusable solution for the common problems occurs in software design.

The underlying concept of design patterns has been around in the software engineering industry since the very beginning, but they weren’t really so formalised. Design Patterns: Elements Of Reusable Object-Oriented Software written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides — the famous Gang of Four (GoF) — Provide 23 Design patterns in their Original book

Types of Design Patterns

There are about 26 Patterns. These 26 can be classified into 3 types —

1. Creational: These patterns are designed for class instantiation. They can be either class-creation patterns or object-creational patterns.

2. Structural: Designed with regard to a class’s structure and composition. The main goal of most of these patterns is to increase the functionality of the class(es) involved, without changing much of its composition.

3. Behavioural: These patterns are designed depending on how one class communicates with others.

We will Learn some most important Design Patterns used in javascript

We will learn all Give Design Patterns

1. Builder Pattern

When you create Objects that have so many optional and required fields

  1. Problem
In this Example want to pass name, address value to User Object so we have to pass: undefined for age, phone because User object receive: 4 parameters
new User("Shivam", undefined, undefined, new Address("208001", "Kanpur"));

So how to manage optional parameters? When creating User Object (new User()) . Maintaining correct order of optional parameters is complicated

we first check into the User class definition that 2nd parameter is the phone, 3rd is age so keep them undefined. Then 4th is address. Suppose we have 20 parameters then more complex to remember params order??

To Deal with such problems Builder Pattern used

There is 2 way to solve this problem in javascript -

a. Traditional Builder Pattern

b. Javascript Specific way (More Cleaner for js development)

Traditional Builder Pattern

So not using the User class directly. we will create a Builder Class

Builder Pattern

Let’s create Simple Object with name —

let user = new UserBuilder("Shivam").build();
console.log(user); // Output:"name":"Shivam"}

If Pass: age parameter

let user = new UserBuilder("Shivam").setAge("24").build();
console.log(user); // Output: {"name":"Shivam","age":"24"}

Pass age, phone and address parameters

let user = new UserBuilder("Shivam").setAge("24").setPhone("7777777777").setAddress("208001", "kanpur").build();
console.log(user); // Output {"name":"Shivam","age":"24","phone":"7777777777","address":"208001"}

Javascript Specific way

Use Destructure syntax in parameter to achieve Builder pattern feature

Just Pass required parameters not optional

Javascript Way to achieve Builder Pattern
let user = new User("Shivam", {age: 25, address: new Address("209303", "Rura"), phone: "7272727272"})Output: {"name":"Shivam","age":25,"phone":"7272727272","address":{"zip":"209303","street":"Rura"}}

To use a default value if some parameter is not passed —

constructor(name, {age, phone='777777777', address} = {})

2. Singleton Design Patterns

Create a Single Object that has shared among different resources threw out our application without recreating that object or losing the information within it

This can create some problem If creating Global variables like

  1. We can not change it freely because all our Project depends on that single Object.

2. Code can be in Race Condition if a global Variable is changing from different part of our Application at the same time

There are many other use cases where we can use Singelton Design Pattern, Let’s understand by this example why Singelton pattern can be used there

PROBLEM:- Suppose we have a logger function for logging the project (Without Singleton pattern)

Create Files — logger.js, app.js, first.js, second.js

logger.js

Now when generating a log, in first.js, second.js we are creating a new instance of logger class by — new Logger();

From app.js when calling —

first(): It creates a new instance of Logger and this.logs = [];second(): It again creates a new instance of Logger that's why printLogout() function returns: 0

Solve this problem by Singleton Design pattern

In javascript, we can create Singleton Object by —

Create Singleton Class

We create an instance in the logger.js and it will be used in all files —

const logger = new Logger()
No need to create an instance in first.js and second.js

Singleton Pattern can be used in many use cases like —

When creating logger Function, Generic HTTP Methods 
Angular Services are also Singleton

3. Factory Pattern

A factory is just an Object that creates different Objects

So Why we need an Object to create Object why not directly create Object using the new keyword ??

  1. Factory allows us to handle an Object in a centralized location. No need to use new keywords everywhere on code to create Objects.
  2. Keeps code clean and concise

Let’s take an example

A company have 2 types of Employees
a. developer
b. Testers

Need a clean and concise way of creating new Employees then insert them in Database. (For now, let’s take Array).

Factory Pattern example

Create a Factory for generating — Developer and Tester Objects.

EmployeeFactory creates 2 types of Objects —

1. Developer (When type: 1 receives)
2. Tester (When type: 2 receives)
Exactly we can create as many types of Employee like -Designers, Analyst etc..

Let’s create a Developer Object using factory —

let empObj = new EmployeeFactory();
let emp = empObj.create("Shivam", 1);
Output:: Hi, I am Shivam and I am a Developer

Another Example:Create 5 Objects using EmployeeFactory, keep them in Array

Factory Example

4. Facade Pattern

Facade pattern hides the complexities of the system and provides an interface to the client using which the client can access the system. This type of design pattern comes under structural pattern as this pattern adds an interface to existing system to hide its complexities

To Make it easy to change our code in future. We create facade between our complex code and our Actual business logic.

So in the facade, we clean up the code and put ugly code in a function (called Facade)

Facade provides interface: to access Subsystem Easily

Example

fetch(): API built in the browser hide complexity just provide simple fetch() method

The problem without facade Pattern

Code without Facade implementation

In this code getUsers(), getUserPosts() both use axios.get() which is duplicate so we can write this type of complex logic in new function no need use axios.get() every time

getFetch(): Shows implementation of Facade design pattern

What is the benefit of getFetch() method in this example?

  1. We have a central function to put axios.get()
  2. If any time we want to change our library axios() to fetch() so we just need to update our getFetch()

5. Command Pattern

All the fun things you can do with the command pattern. The idea of the command pattern is to create an abstraction between the operations an object can do, its commands, and the actual commands themselves.

This makes it really easy to combine together or chain different commands without having to change the code. The program can dynamically chain and combine these actions.

The best part is since each command is its own object you can easily implement an undo function for each command and make a set of undo-able actions.

First Understand Problem without Command Pattern. Simple Calculator example with 2 operations — add, subtract

Simple Calculator class

Now in this code, if we want to undo some calculation so how to do?

Wana see history of operations

Want to perform add and subtract together with chaining?

  1. Create a class for each operation of calculator like- AddCommand, SubtractCommand etc

2. Create an interface class Calculator which will execute all these class as a command. The external user only call the Calculator class

Command Pattern Example

Where the Command pattern can be used ?? Examples —

  1. If required Do operation and then Undo operation
  2. Playback and rewind so we can create commands
  3. In-Text editor many places this pattern can be used — Shortcuts command(ctrl+b, ctrl+r ) etc

6. Observer Pattern

Observer pattern is used when there is one-to-many relationship between objects such as if one object is modified, its depenedent objects are to be notified automatically. Observer pattern falls under behavioral pattern category
Subject — Subscribe/unsubscribe Observers

We define One to many dependency relationships from One Object known as the Subject to many other Objects known as Observers

These Observers can be the function which watches the subject and waits for some signal or trigger from the Subject to run like an Event listener

Observer Pattern used in Event Handling System. Angular also Use Observable

> When Api response come back from server
> Realtime Data listen using Observables
Understand Subject and Observers

Observer Pattern Example -

First Create a Subject class.

Create an Array this.observers = [] : This will store Observer functions

subscribe(): Method will push Observer functions to observers Array

unsubscribe(): Remove Selected observer function From Array

fire(): will call all subscriber methods

7. Null Object Pattern

One of the easiest to implement design patterns is the Null Object Pattern. This pattern is all about handling the null keyword in a way that removes all of those nasty if (object == null) checks from your code. It also makes handling default values for null objects a breeze.

Suppose there is a User class

class User {
constructor(id, name) {
this.id = id;
this.name = name;
}
hasAccess() {
return this.name === "Shivam"; }
}
const users = [ new User(1, "Bob"), new User(2, "John")]

User with the name: ‘Bob’ has access

As we can see in this example we need to check: null multiple times. So lets create a Null Object same as User Object with some default value

class NullUser {
constructor() {
this.id= -1;
this.name= "Guest"
}
hasAccess() {
return false;
}
}

Instead of returning null will return NullUser Object so default properties will be meet like — hasAccess, id, name in the calling function. This is main benifit of Null Object pattern

Complete Example —

printUser(1): Hello Bob You have access…

Thanks for reading this article. Give a clap if you like this. Please write in the comment section for any Question or suggestion.

Subscribe for more cool stuff !!

--

--

Shivam Gupta

Full Stack Engineer (Web/App) working on different JS Technologies & frameworks— Angular, Node, Typescript, Ionic, Firebase, AWS, ElK...Love to write cool stuff