Open In App

Decorator Design Pattern in JavaScript

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

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

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.

Use Cases for the Decorator Pattern in JavaScript

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

Key Components of the Decorator Design Pattern in JavaScript

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):

// 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):

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

3. Decorator (ProfileDecorator):

// 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):

// 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:

// 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();
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:

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:


Article Tags :