TypeScript Prototype Design Pattern
What is prototype design pattern?
The Prototype design pattern is a creational design pattern. It provides the ability to clone objects without rebuilding them from scratch. With the prototype design pattern, the cloned objects do not form dependencies with the original objects’ relationships.
There are a few terminologies in the prototype design pattern. These are:
- Prototype Interface: Define the requirements for the clone method.
- Concrete Prototype: It implements the prototype interface and handles the requirements defined in the prototype interface.
- Subclass Prototype: When defined, it overrides the cloning method in the concrete prototype to further alter the cloned object.
- Client: It’s the application or function that initiates the cloning process.
When should the prototype design pattern be used?
The prototype design pattern can be used when the objects that are going to be cloned do not need to depend on concrete classes. By utilizing the prototype interface, objects can be cloned without creating the clone object from scratch.
This approach not only enables the effortless replication of objects but also allows for alterations in the cloned instances by manipulating clone classes, resulting in the creation of diverse types of clones.
How to implement prototype design pattern in TypeScript
Let’s imagine a scenario where we have a social media membership application. We decide to add a new feature — premium membership. For this feature to work, we need to assign subscription levels to users and specify their subscription level. To achieve this, we plan to replicate user objects to fit our premium structure. However, attempting to rebuild users from scratch for our new feature could lead to complications due to the complexity of our existing user base. This situation hampers the correct construction of users.
Instead of trying to rebuild users and recreate the same complex structures, we opt to employ the prototype design pattern. Through this approach, we establish a connection with the user at a higher level using a prototype interface. With this interface, we copy our users without reconstructing their intricate structures from scratch. Essentially, we copied their current structure in the user base with the help of the prototype interface.
Prototype design pattern diagram
Prototype design pattern code
// Interface Prototype
interface IUserPrototype {
clone(): IUserPrototype;
}
// ConcretePrototype
class UserProfile implements IUserPrototype {
private username: string;
constructor(username: string) {
this.username = username;
}
clone(): UserProfile {
return new UserProfile(this.username);
}
getUsername(): string {
return this.username;
}
}
// SubclassPrototype
class PremiumUserProfile extends UserProfile {
private subLvl: string;
constructor(username: string, subLvl: string) {
super(username);
this.subLvl = subLvl;
}
clone(): PremiumUserProfile {
return new PremiumUserProfile(this.getUsername(), this.subLvl);
}
getSubLvl(): string {
return this.subLvl;
}
}
// Client
const basicUser = new UserProfile("Ibrahim");
//Basic User: Ibrahim
console.log("Basic User:", basicUser.getUsername());
const clonedBasicUser = basicUser.clone();
//Cloned Basic User: Ibrahim
console.log("Cloned Basic User:", clonedBasicUser.getUsername());
const premiumUser = new PremiumUserProfile(clonedBasicUser.getUsername(), "Premium");
//Premium User: Ibrahim - Premium
console.log("Premium User:", premiumUser.getUsername(), "-", premiumUser.getSubLvl());