Skip to content
geeksforgeeks
  • Tutorials
    • Python
    • Java
    • Data Structures & Algorithms
    • ML & Data Science
    • Interview Corner
    • Programming Languages
    • Web Development
    • CS Subjects
    • DevOps And Linux
    • Software and Tools
    • School Learning
    • Practice Coding Problems
  • Go Premium
  • System Design Tutorial
  • What is System Design
  • System Design Life Cycle
  • High Level Design HLD
  • Low Level Design LLD
  • Design Patterns
  • UML Diagrams
  • System Design Interview Guide
  • Scalability
  • Databases
Open In App
Next Article:
Decorator Design Pattern
Next article icon

Decorator Design Pattern in JavaScript

Last Updated : 05 Apr, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

The Decorator Design Pattern in JavaScript is a structural design pattern that allows behavior to be added to individual objects dynamically, without affecting the behavior of other objects from the same class. It involves creating a set of decorator classes that are used to wrap concrete components.

Decorator-Design-Pattern-in-Javascript

Important Topics for the Decorator Design Pattern in JavaScript

  • What is a Decorator Design Pattern in JavaScript?
  • Characteristics of the Decorator Pattern in JavaScript
  • Real-World Example of Decorator Design Pattern in JavaScript
  • Use Cases for the Decorator Pattern in JavaScript
  • Key Components of the Decorator Design Pattern in JavaScript
  • Example of Decorator Design Pattern in JavaScript
  • Advantages of the Decorator Design Pattern in JavaScript
  • Disadvantages of the Decorator Design Pattern in JavaScript

What is a Decorator Design Pattern in JavaScript?

The Decorator Design Pattern is a structural design pattern used in software development. It allows behavior to be added to individual objects, dynamically, without affecting the behavior of other objects from the same class. This pattern is useful when you need to add functionality to objects in a flexible and reusable way.

Characteristics of the Decorator Pattern in JavaScript

  • This pattern promotes flexibility and extensibility in software systems by allowing developers to compose objects with different combinations of functionalities at runtime.
  • It adheres to the open/closed principle, as new decorators can be added without modifying existing code, making it a powerful tool for building modular and customizable software components.
  • The Decorator Pattern is commonly used in scenarios where a variety of optional features or behaviors need to be added to objects in a flexible and reusable manner, such as in text formatting, graphical user interfaces, or customization of products like coffee or ice cream.

Real-World Example of Decorator Design Pattern in JavaScript

Consider a video streaming platform where users can watch movies and TV shows. Each video content may have additional features or options available, such as subtitles, language preferences, video quality options, and audio enhancements.

  • In this scenario, the base component is the video content itself, while the decorators represent the various additional features that users can enable or customize.
  • For example, a user might select the option to enable subtitles, change the language of the audio track, or adjust the video quality settings.
  • Each of these options acts as a decorator that enhances the viewing experience without altering the underlying video content.
  • By using the Decorator pattern, the streaming platform can dynamically apply these additional features to the video content based on user preferences, providing a customizable viewing experience.

Use Cases for the Decorator Pattern in JavaScript

Below are some of the use cases of Decorator Design Pattern in JavaScript:

  • Extending Functionality: Dynamically add additional functionality to objects or functions without modifying their original code, promoting code reusability and maintainability.
  • Browser APIs: Extend the functionality of DOM elements or browser APIs provided by third-party libraries without altering their original implementations, facilitating the integration of external libraries into web applications.
  • Middleware in Express.js: Implement middleware functions in web development using Node.js and Express.js to add cross-cutting concerns such as logging, error handling, or authentication to route handlers without modifying their core logic.
  • Logging and Profiling: Add logging, profiling, or error handling functionality to functions or methods in a non-intrusive way, allowing for easier debugging and monitoring of code execution.
  • Caching and Memoization: Improve performance by applying decorators to functions to implement caching or memoization strategies, where the result of a function call is cached for future invocations with the same input parameters

Key Components of the Decorator Design Pattern in JavaScript

  • Component Interface: This is an abstract class or interface that defines the common interface for both the concrete components and decorators. It specifies the operations that can be performed on the objects.
  • Concrete Component: These are the basic objects or classes that implement the Component interface. They are the objects to which we want to add new behavior or responsibilities.
  • Decorator: This is an abstract class that also implements the Component interface and has a reference to a Component object. Decorators are responsible for adding new behaviors to the wrapped Component object.
  • Concrete Decorator: These are the concrete classes that extend the Decorator class. They add specific behaviors or responsibilities to the Component. Each Concrete Decorator can add one or more behaviors to the Component.

Example of Decorator Design Pattern in JavaScript

Below is the problem statement to understand the Decorator Design Pattern in JavaScript:

Imagine you are developing a web application where users can create and customize their profiles. Each user has basic information such as name, email, and profile picture, but they can also choose to add optional features such as a bio, social media links, or a profile theme. You want to implement a system that allows users to dynamically customize their profiles with these optional features while keeping the codebase clean and maintainable.

The Decorator Design Pattern is ideal for this scenario because it allows you to add optional features to individual profile objects dynamically without modifying the core profile class. This promotes code reusability, flexibility, and maintainability, as new features can be easily added or removed without affecting the existing code.

DecoratorPatternJSClassDiagram-2

1. Component Interface (Profile):

  • This is the base component interface representing a user profile.
  • It contains basic properties such as name, email, and profile picture, along with a display() method to print profile information.
JavaScript
// Profile interface representing the base component
class Profile {
    constructor(name, email, profilePicture) {
        this.name = name;
        this.email = email;
        this.profilePicture = profilePicture;
    }

    display() {
        console.log(`Name: ${this.name}`);
        console.log(`Email: ${this.email}`);
        console.log(`Profile Picture: ${this.profilePicture}`);
    }
}

2. Concrete Component (BasicProfile):

  • BasicProfile is a concrete subclass of Profile.
  • It inherits properties and methods from the base Profile class and does not contain any additional features.
JavaScript
// Concrete component representing basic profile without any additional features
class BasicProfile extends Profile {
    constructor(name, email, profilePicture) {
        super(name, email, profilePicture);
    }
}

3. Decorator (ProfileDecorator):

  • ProfileDecorator is an abstract decorator class implementing the Profile interface.
  • It maintains a reference to the decorated Profile object and delegates method calls to it.
JavaScript
// Decorator class implementing the Profile interface
class ProfileDecorator extends Profile {
    constructor(profile) {
        super(profile.name, profile.email, profile.profilePicture);
        this.profile = profile;
    }

    display() {
        this.profile.display();
    }
}

4. Concrete Decorators (BioDecorator, SocialMediaDecorator):

  • BioDecorator and SocialMediaDecorator are concrete decorators extending ProfileDecorator.
  • They add additional features (bio, social media links) to the profile and override the display() method to include the new features.
JavaScript
// Concrete decorator adding a bio to the profile
class BioDecorator extends ProfileDecorator {
    constructor(profile, bio) {
        super(profile);
        this.bio = bio;
    }

    display() {
        super.display();
        console.log(`Bio: ${this.bio}`);
    }
}

// Concrete decorator adding social media links to the profile
class SocialMediaDecorator extends ProfileDecorator {
    constructor(profile, socialMediaLinks) {
        super(profile);
        this.socialMediaLinks = socialMediaLinks;
    }

    display() {
        super.display();
        console.log(`Social Media Links: ${this.socialMediaLinks}`);
    }
}

Complete Code for the above example:

Below is the complete code of the above problem statement:

JavaScript
// Profile interface representing the base component
class Profile {
    constructor(name, email, profilePicture) {
        this.name = name;
        this.email = email;
        this.profilePicture = profilePicture;
    }

    display() {
        console.log(`Name: ${this.name}`);
        console.log(`Email: ${this.email}`);
        console.log(`Profile Picture: ${this.profilePicture}`);
    }
}

// Concrete component representing basic profile without any additional features
class BasicProfile extends Profile {
    constructor(name, email, profilePicture) {
        super(name, email, profilePicture);
    }
}

// Decorator class implementing the Profile interface
class ProfileDecorator extends Profile {
    constructor(profile) {
        super(profile.name, profile.email, profile.profilePicture);
        this.profile = profile;
    }

    display() {
        this.profile.display();
    }
}

// Concrete decorator adding a bio to the profile
class BioDecorator extends ProfileDecorator {
    constructor(profile, bio) {
        super(profile);
        this.bio = bio;
    }

    display() {
        super.display();
        console.log(`Bio: ${this.bio}`);
    }
}

// Concrete decorator adding social media links to the profile
class SocialMediaDecorator extends ProfileDecorator {
    constructor(profile, socialMediaLinks) {
        super(profile);
        this.socialMediaLinks = socialMediaLinks;
    }

    display() {
        super.display();
        console.log(`Social Media Links: ${this.socialMediaLinks}`);
    }
}

// Usage
let basicProfile = new BasicProfile("John Doe", "john@example.com", "profile.jpg");
basicProfile.display();

let profileWithBio = new BioDecorator(basicProfile, "I'm a software engineer.");
profileWithBio.display();

let profileWithSocialMedia = new SocialMediaDecorator(basicProfile, "@johndoe");
profileWithSocialMedia.display();
Output
Name: John Doe
Email: john@example.com
Profile Picture: profile.jpg

Name: John Doe
Email: john@example.com
Profile Picture: profile.jpg
Bio: I'm a software engineer.

Name: John Doe
Email: john@example.com
Profile Picture: profile.jpg
Social Media Links: @johndoe

Advantages of the Decorator Design Pattern in JavaScript

The decorator pattern is a structural design pattern that allows us to add behavior to individual objects, either statically or dynamically, without affecting the behavior of other objects from the same class. It is often used to extend the functionality of classes in a flexible and reusable way. Here are some of the advantages of the decorator pattern:

  • Open-Closed Principle: The decorator pattern follows the open-closed principle, which states that classes should be open for extension but closed for modification. This means you can introduce new functionality to an existing class without changing its source code.
  • Flexibility: It allows you to add or remove responsibilities (i.e., behaviors) from objects at runtime. This flexibility makes it easy to create complex object structures with varying combinations of behaviors.
  • Reusable Code: Decorators are reusable components. You can create a library of decorator classes and apply them to different objects and classes as needed, reducing code duplication.
  • Composition over Inheritance: Unlike traditional inheritance, which can lead to a deep and inflexible class hierarchy, the decorator pattern uses composition. You can compose objects with different decorators to achieve the desired functionality, avoiding the drawbacks of inheritance, such as tight coupling and rigid hierarchies.
  • Dynamic Behavior Modification: Decorators can be applied or removed at runtime, providing dynamic behavior modification for objects. This is particularly useful when you need to adapt an object's behavior based on changing requirements or user preferences.
  • Clear Code Structure: The Decorator pattern promotes a clear and structured design, making it easier for developers to understand how different features and responsibilities are added to objects.

Disadvantages of the Decorator Design Pattern in JavaScript

While the Decorator pattern offers several advantages, it also has some disadvantages and trade-offs to consider when deciding whether to use it in a particular software design. Here are some of the disadvantages of the Decorator pattern:

  • Complexity: As you add more decorators to an object, the code can become more complex and harder to understand. The nesting of decorators can make the codebase difficult to navigate and debug, especially when there are many decorators involved.
  • Increased Number of Classes: When using the Decorator pattern, you often end up with a large number of small, specialized decorator classes. This can lead to a proliferation of classes in your codebase, which may increase maintenance overhead.
  • Order of Decoration: The order in which decorators are applied can affect the final behavior of the object. If decorators are not applied in the correct order, it can lead to unexpected results. Managing the order of decorators can be challenging, especially in complex scenarios.
  • Potential for Overuse: Because it's easy to add decorators to objects, there is a risk of overusing the Decorator pattern, making the codebase unnecessarily complex. It's important to use decorators judiciously and only when they genuinely add value to the design.
  • Limited Support in Some Languages: Some programming languages may not provide convenient support for implementing decorators. Implementing the pattern can be more verbose and less intuitive in such languages.



Next Article
Decorator Design Pattern

K

kartik
Improve
Article Tags :
  • Design Pattern
  • System Design

Similar Reads

    Decorator Method Design Pattern in Java
    A structural design pattern called the Decorator Design Pattern enables the dynamic addition of functionality to specific objects without changing the behavior of other objects in the same class. To wrap concrete components, a collection of decorator classes must be created. Decorator Method Design
    10 min read
    Decorator Design Pattern
    The Decorator Design Pattern is a structural design pattern that allows behavior to be added to individual objects dynamically, without affecting the behavior of other objects from the same class. It involves creating a set of decorator classes that are used to wrap concrete components.Important Top
    9 min read
    Adapter Method | JavaScript Design Patterns
    Adapter Pattern in JavaScript is a structural design pattern that allows you to make one interface or object work with another that has a different interface. It acts as a bridge, enabling the compatibility of two systems that would not naturally work together. Important Topics for the Adapter Metho
    8 min read
    Behavioral Design Pattern | JavaScript Design Pattern
    Behavioral design patterns are a subset of design patterns in software engineering that deal with the interaction and responsibilities of objects. These patterns focus on how objects communicate and work together to achieve common tasks. Important Topics for the Behavioral Design Pattern in JavaScri
    8 min read
    Builder Method | JavaScript Design Pattern
    The Builder design pattern is a creational design pattern used to construct complex objects by separating the construction process from the actual representation. It's especially useful when an object requires multiple steps or configurations to be created. Important Topics for the Builder Design Pa
    9 min read
    Command Method | JavaScript Design Patterns
    The command method is a behavioral design pattern that encapsulates an incoming request into a standalone object. This object contains all the necessary information to perform a request including the method to call and parameters. Important Topics for the Command Method in JavaScript Design Patterns
    6 min read
`; $(commentSectionTemplate).insertBefore(".article--recommended"); } loadComments(); }); }); function loadComments() { if ($("iframe[id*='discuss-iframe']").length top_of_element && top_of_screen articleRecommendedTop && top_of_screen articleRecommendedBottom)) { if (!isfollowingApiCall) { isfollowingApiCall = true; setTimeout(function(){ if (loginData && loginData.isLoggedIn) { if (loginData.userName !== $('#followAuthor').val()) { is_following(); } else { $('.profileCard-profile-picture').css('background-color', '#E7E7E7'); } } else { $('.follow-btn').removeClass('hideIt'); } }, 3000); } } }); } $(".accordion-header").click(function() { var arrowIcon = $(this).find('.bottom-arrow-icon'); arrowIcon.toggleClass('rotate180'); }); }); window.isReportArticle = false; function report_article(){ if (!loginData || !loginData.isLoggedIn) { const loginModalButton = $('.login-modal-btn') if (loginModalButton.length) { loginModalButton.click(); } return; } if(!window.isReportArticle){ //to add loader $('.report-loader').addClass('spinner'); jQuery('#report_modal_content').load(gfgSiteUrl+'wp-content/themes/iconic-one/report-modal.php', { PRACTICE_API_URL: practiceAPIURL, PRACTICE_URL:practiceURL },function(responseTxt, statusTxt, xhr){ if(statusTxt == "error"){ alert("Error: " + xhr.status + ": " + xhr.statusText); } }); }else{ window.scrollTo({ top: 0, behavior: 'smooth' }); $("#report_modal_content").show(); } } function closeShareModal() { const shareOption = document.querySelector('[data-gfg-action="share-article"]'); shareOption.classList.remove("hover_share_menu"); let shareModal = document.querySelector(".hover__share-modal-container"); shareModal && shareModal.remove(); } function openShareModal() { closeShareModal(); // Remove existing modal if any let shareModal = document.querySelector(".three_dot_dropdown_share"); shareModal.appendChild(Object.assign(document.createElement("div"), { className: "hover__share-modal-container" })); document.querySelector(".hover__share-modal-container").append( Object.assign(document.createElement('div'), { className: "share__modal" }), ); document.querySelector(".share__modal").append(Object.assign(document.createElement('h1'), { className: "share__modal-heading" }, { textContent: "Share to" })); const socialOptions = ["LinkedIn", "WhatsApp","Twitter", "Copy Link"]; socialOptions.forEach((socialOption) => { const socialContainer = Object.assign(document.createElement('div'), { className: "social__container" }); const icon = Object.assign(document.createElement("div"), { className: `share__icon share__${socialOption.split(" ").join("")}-icon` }); const socialText = Object.assign(document.createElement("span"), { className: "share__option-text" }, { textContent: `${socialOption}` }); const shareLink = (socialOption === "Copy Link") ? Object.assign(document.createElement('div'), { role: "button", className: "link-container CopyLink" }) : Object.assign(document.createElement('a'), { className: "link-container" }); if (socialOption === "LinkedIn") { shareLink.setAttribute('href', `https://www.linkedin.com/sharing/share-offsite/?url=${window.location.href}`); shareLink.setAttribute('target', '_blank'); } if (socialOption === "WhatsApp") { shareLink.setAttribute('href', `https://api.whatsapp.com/send?text=${window.location.href}`); shareLink.setAttribute('target', "_blank"); } if (socialOption === "Twitter") { shareLink.setAttribute('href', `https://twitter.com/intent/tweet?url=${window.location.href}`); shareLink.setAttribute('target', "_blank"); } shareLink.append(icon, socialText); socialContainer.append(shareLink); document.querySelector(".share__modal").appendChild(socialContainer); //adding copy url functionality if(socialOption === "Copy Link") { shareLink.addEventListener("click", function() { var tempInput = document.createElement("input"); tempInput.value = window.location.href; document.body.appendChild(tempInput); tempInput.select(); tempInput.setSelectionRange(0, 99999); // For mobile devices document.execCommand('copy'); document.body.removeChild(tempInput); this.querySelector(".share__option-text").textContent = "Copied" }) } }); // document.querySelector(".hover__share-modal-container").addEventListener("mouseover", () => document.querySelector('[data-gfg-action="share-article"]').classList.add("hover_share_menu")); } function toggleLikeElementVisibility(selector, show) { document.querySelector(`.${selector}`).style.display = show ? "block" : "none"; } function closeKebabMenu(){ document.getElementById("myDropdown").classList.toggle("show"); }
geeksforgeeks-footer-logo
Corporate & Communications Address:
A-143, 7th Floor, Sovereign Corporate Tower, Sector- 136, Noida, Uttar Pradesh (201305)
Registered Address:
K 061, Tower K, Gulshan Vivante Apartment, Sector 137, Noida, Gautam Buddh Nagar, Uttar Pradesh, 201305
GFG App on Play Store GFG App on App Store
Advertise with us
  • Company
  • About Us
  • Legal
  • Privacy Policy
  • In Media
  • Contact Us
  • Advertise with us
  • GFG Corporate Solution
  • Placement Training Program
  • Languages
  • Python
  • Java
  • C++
  • PHP
  • GoLang
  • SQL
  • R Language
  • Android Tutorial
  • Tutorials Archive
  • DSA
  • Data Structures
  • Algorithms
  • DSA for Beginners
  • Basic DSA Problems
  • DSA Roadmap
  • Top 100 DSA Interview Problems
  • DSA Roadmap by Sandeep Jain
  • All Cheat Sheets
  • Data Science & ML
  • Data Science With Python
  • Data Science For Beginner
  • Machine Learning
  • ML Maths
  • Data Visualisation
  • Pandas
  • NumPy
  • NLP
  • Deep Learning
  • Web Technologies
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • ReactJS
  • NextJS
  • Bootstrap
  • Web Design
  • Python Tutorial
  • Python Programming Examples
  • Python Projects
  • Python Tkinter
  • Python Web Scraping
  • OpenCV Tutorial
  • Python Interview Question
  • Django
  • Computer Science
  • Operating Systems
  • Computer Network
  • Database Management System
  • Software Engineering
  • Digital Logic Design
  • Engineering Maths
  • Software Development
  • Software Testing
  • DevOps
  • Git
  • Linux
  • AWS
  • Docker
  • Kubernetes
  • Azure
  • GCP
  • DevOps Roadmap
  • System Design
  • High Level Design
  • Low Level Design
  • UML Diagrams
  • Interview Guide
  • Design Patterns
  • OOAD
  • System Design Bootcamp
  • Interview Questions
  • Inteview Preparation
  • Competitive Programming
  • Top DS or Algo for CP
  • Company-Wise Recruitment Process
  • Company-Wise Preparation
  • Aptitude Preparation
  • Puzzles
  • School Subjects
  • Mathematics
  • Physics
  • Chemistry
  • Biology
  • Social Science
  • English Grammar
  • Commerce
  • World GK
  • GeeksforGeeks Videos
  • DSA
  • Python
  • Java
  • C++
  • Web Development
  • Data Science
  • CS Subjects
@GeeksforGeeks, Sanchhaya Education Private Limited, All rights reserved
We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Cookie Policy & Privacy Policy
Lightbox
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
geeksforgeeks-suggest-icon
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.
geeksforgeeks-improvement-icon
Suggest Changes
min 4 words, max Words Limit:1000

Thank You!

Your suggestions are valuable to us.

What kind of Experience do you want to share?

Interview Experiences
Admission Experiences
Career Journeys
Work Experiences
Campus Experiences
Competitive Exam Experiences