What is decorator pattern in Node.js?

Design patterns are incredibly useful and one of the best programming practices followed by software developers. They provide solutions to those problems that are recurrent during software development. They are also known as GoF (Gang of Four) Design Patterns, and there are three software design patterns:

  • Creational

  • Behavioral

  • Structural

We’ll discuss one of the structural patterns called the decorator pattern.

Decorator pattern

The decorator pattern adds functionality to our classes without directly modifying or inheriting from them. Using this pattern, we can augment the behavior of an already existing object dynamically. Without affecting the other objects, the behavior is explicitly augmented to only those objects that we want to decorate.

The components that are typically used in the decorator pattern are the following:

  • Component: The interface and abstract class for the component.

  • Concrete component: The objects that implement the Component interface and that are being decorated.

  • Decorator: The abstract class that also acts as a base class for all the decorators.

  • Concrete decorator: The class that adds functionality to the objects.

  • Client: The part that interacts with the interface of the component.

Workflow components of the decorator pattern
Workflow components of the decorator pattern

The above illustration shows that the Component is the main interface class of the object functionalities. The ConcreteComponent implements the methods of the Component interface. The Decorator implements the Component interface, and it has a reference to the Component interface class, which allows the ConcreteDecorator to add more functionality to the object.

Let’s implement the pattern for better understanding.

Implementation of the decorator pattern

Consider a simple scenario in which we implement the decorator pattern to add a pagination functionality to a simple page class. We’ll implement the following components in Node.js:

  • PageComponent class that acts as a Component

  • Page class that acts as a ConcreteComponent

  • PaginationDecorator class that acts as a Decorator and ConcreteDecorator

// Component
class PageComponent {
display() {
throw new Error("This method should be overridden");
}
}
// ConcreteComponent
class Page extends PageComponent
{
constructor(content) {
super();
this.content = content
}
display() {
console.log(this.content)
}
}
// Decorator and ConcreteDecorator
class PaginationDecorator extends PageComponent
{
constructor(page, pageSize) {
super();
this.page = page
this.pageSize = pageSize
this.currentPage = 1
}
// Method to display pages
display() {
const start = (this.currentPage - 1) * this.pageSize
const end = start + this.pageSize
console.log(this.page.content.substring(start, end))
}
// Method to show the next page content
nextPage() {
this.currentPage++
this.display()
}
// Method to show the previous page content
previousPage() {
if (this.currentPage > 1) {
this.currentPage--
}
this.display()
}
}
// Create a new Page instance with some content
const content = "Educative — Leading online learning platform made by developers, created for developers. Free Trial. Text-based courses with embedded coding environments help you learn without the fluff."
const page = new Page(content)
// Decorate the Page instance with pagination
const pagination = new PaginationDecorator(page, 50)
// Display the first page
pagination.display()
// Display the next page
pagination.nextPage()
// Display the previous page
pagination.previousPage()

Explanation

  • Lines 2–6: We created an interface class PageComponent with a display method.

  • Lines 9–19: We created a simple class Page that extends the PageComponent. It has a constructor that initializes the page with content and a display method to print the content of the page to the console.

  • Lines 22–51: We created a decorator class PaginationDecorator that extends the PageComponent and wraps the instance of the Page class and adds the pagination functionality. The PaginationDecorator class constructor accepts a Page object and a pageSize to determine the amount of content displayed per page. This class has three methods: display(), nextPage() and previousPage(). The display() method shows the current page, nextPage() method is to move to the next page to show its content, and previousPage() method is to go back to the previous page to show its content.

  • Lines 54–67: We created an instance of Page class, added the content, and wrapped this instance with the PaginationDecorator decorator, specifying a page size of 50 characters. We then used the display() method to show the current page’s content, the nextPage() method to display the following page, and the previousPage() method to display the previous page on the console.

Limitations

There are a few disadvantages of the decorator pattern that should be kept in mind while using the pattern:

  • It increases complexity as we create multiple classes for the decorators and components.

  • All the decorators and concrete components need to follow a single interface, which results in interface constraints.

  • Managing dependency between components and decorators sometimes becomes very tough if we work on large components.

Conclusion

The decorator pattern is particularly useful for scenarios where we need to build a flexible design, as it allows us to add objects dynamically. Its proper use, while keeping in mind its limitations, makes it a powerful tool in our Node.js applications.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved