Thanks! We'll be in touch in the next 12 hours
Oops! Something went wrong while submitting the form.

The 7 Most Useful Design Patterns in ES6 (and how you can implement them)

After spending a couple of years in JavaScript development, I’ve realized how incredibly important design patterns are, in modern JavaScript (ES6). And I'd love to share my experience and knowledge on the subject, hoping you’d make this a critical part of your development process as well.

Note: All the examples covered in this post are implemented with ES6 features, but you can also integrate the design patterns with ES5.

At Velotio, we always follow best practices to achieve highly maintainable and more robust code. And we are strong believers of using design patterns as one of the best ways to write clean code. 

In the post below, I’ve listed the most useful design patterns I’ve implemented so far and how you can implement them too:

1. Module

The module pattern simply allows you to keep units of code cleanly separated and organized. 

Modules promote encapsulation, which means the variables and functions are kept private inside the module body and can't be overwritten.

Creating a module in ES6 is quite simple.

CODE: https://gist.github.com/velotiotech/3ebc7ebb406f054c7dc98f67e8a9ffba.js

CODE: https://gist.github.com/velotiotech/1bb84238fe77ac68d37072d8ea0cf6d3.js

ES6 also allows us to export the module as default. The following example gives you a better understanding of this.

CODE: https://gist.github.com/velotiotech/e7dc5e320619e28f1d0e771b684008a8.js

CODE: https://gist.github.com/velotiotech/502fb467a4f902705aaed7184286f049.js

There is a great article written on the features of ES6 modules here.

2. Factory

Imagine creating a Notification Management application where your application currently only allows for a notification through Email, so most of the code lives inside the EmailNotification class. And now there is a new requirement for PushNotifications. So, to implement the PushNotifications, you have to do a lot of work as your application is mostly coupled with the EmailNotification. You will repeat the same thing for future implementations.

To solve this complexity, we will delegate the object creation to another object called factory.

CODE: https://gist.github.com/velotiotech/58cec3d85b881ebbaff81a1ebc20b96e.js

3. Observer

(Also known as the publish/subscribe pattern.)

An observer pattern maintains the list of subscribers so that whenever an event occurs, it will notify them. An observer can also remove the subscriber if the subscriber no longer wishes to be notified.

On YouTube, many times, the channels we’re subscribed to will notify us whenever a new video is uploaded.

CODE: https://gist.github.com/velotiotech/06814919d613a19c19bed4c04ec92fec.js

4. Mediator

The mediator pattern provides a unified interface through which different components of an application can communicate with each other.

If a system appears to have too many direct relationships between components, it may be time to have a central point of control that components communicate through instead. 

The mediator promotes loose coupling. 

A real-time analogy could be a traffic light signal that handles which vehicles can go and stop, as all the communications are controlled from a traffic light.

Let’s create a chatroom (mediator) through which the participants can register themselves. The chatroom is responsible for handling the routing when the participants chat with each other. 

CODE: https://gist.github.com/velotiotech/43dbe01ca3df17d32bfff73d4b167f13.js

5. Command

In the command pattern, an operation is wrapped as a command object and passed to the invoker object. The invoker object passes the command to the corresponding object, which executes the command.

The command pattern decouples the objects executing the commands from objects issuing the commands. The command pattern encapsulates actions as objects. It maintains a stack of commands whenever a command is executed, and pushed to stack. To undo a command, it will pop the action from stack and perform reverse action.

You can consider a calculator as a command that performs addition, subtraction, division and multiplication, and each operation is encapsulated by a command object.

CODE: https://gist.github.com/velotiotech/3cd411bfd7a6070b13f135f6cb90ca84.js

6. Facade

The facade pattern is used when we want to show the higher level of abstraction and hide the complexity behind the large codebase.

A great example of this pattern is used in the common DOM manipulation libraries like jQuery, which simplifies the selection and events adding mechanism of the elements.

CODE: https://gist.github.com/velotiotech/a3a78d0c28bf22b4a23ae3a83c5ecd45.js

Though it seems simple on the surface, there is an entire complex logic implemented when performing the operation.

The following Account Creation example gives you clarity about the facade pattern: 

CODE: https://gist.github.com/velotiotech/849964d1e2f93c985bf987a2bf8a987a.js

7. Adapter

The adapter pattern converts the interface of a class to another expected interface, making two incompatible interfaces work together. 

With the adapter pattern, you might need to show the data from a 3rd party library with the bar chart representation, but the data formats of the 3rd party library API and the display bar chart are different. Below, you’ll find an adapter that converts the 3rd party library API response to Highcharts’ bar representation:

CODE: https://gist.github.com/velotiotech/972ee9dc0cfbcae341c1dab4ab794442.js

Conclusion

This has been a brief introduction to the design patterns in modern JavaScript (ES6). This subject is massive, but hopefully this article has shown you the benefits of using it when writing code.

Related Articles

1. Cleaner, Efficient Code with Hooks and Functional Programming

2. Building a Progressive Web Application in React [With Live Code Examples]