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.
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.
// 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 ofProfile
.- It inherits properties and methods from the base
Profile
class and does not contain any additional features.
// 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 theProfile
interface.- It maintains a reference to the decorated
Profile
object and delegates method calls to it.
// 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
andSocialMediaDecorator
are concrete decorators extendingProfileDecorator
.- They add additional features (bio, social media links) to the profile and override the
display()
method to include the new features.
// 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
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.
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
Contact Us