Simple Example
First, let's define an interface for cloning.
interface Prototype {
clone(): Prototype;
}
Now, we'll create a concrete class that implements this interface.
class User implements Prototype {
constructor(public name: string, public age: number) {}
clone(): User {
return new User(this.name, this.age);
}
display(): void {
console.log(`Name: ${this.name}, Age: ${this.age}`);
}
}
Here, the User class implements the Prototype interface and provides a clone method to create a copy of the user.
const originalUser = new User("Bilel", 23);
const clonedUser = originalUser.clone();
originalUser.display(); // Name: Bilel, Age: 23
clonedUser.display(); // Name: Bilel, Age: 23
Now, let's deep dive into a more complex example. We'll create a scenario involving a content management system (CMS) where different types of content objects (e.g., articles, videos, podcasts) need to be created and customized frequently. This example will showcase the Prototype Pattern in a richer context.
Complex Example: Content Management System (CMS)
In this CMS example, we'll have different types of content, each with various properties. We'll use the Prototype Pattern to clone these content objects easily.
Step 1: Define the Prototype Interface
interface ContentPrototype {
clone(): ContentPrototype;
}
Step 2: Create Concrete Content Classes
We will create three concrete classes: Article, Video, and Podcast, each implementing the ContentPrototype interface.
class Article implements ContentPrototype {
constructor(
public title: string,
public body: string,
public author: string,
public tags: string[],
public publishDate: Date
) {}
clone(): Article {
return new Article(this.title, this.body, this.author, [...this.tags], new Date(this.publishDate.getTime()));
}
display(): void {
console.log(`Article Title: ${this.title}`);
console.log(`Body: ${this.body}`);
console.log(`Author: ${this.author}`);
console.log(`Tags: ${this.tags.join(", ")}`);
console.log(`Publish Date: ${this.publishDate}`);
}
}
class Video implements ContentPrototype {
constructor(
public title: string,
public url: string,
public duration: number,
public uploader: string,
public publishDate: Date
) {}
clone(): Video {
return new Video(this.title, this.url, this.duration, this.uploader, new Date(this.publishDate.getTime()));
}
display(): void {
console.log(`Video Title: ${this.title}`);
console.log(`URL: ${this.url}`);
console.log(`Duration: ${this.duration} minutes`);
console.log(`Uploader: ${this.uploader}`);
console.log(`Publish Date: ${this.publishDate}`);
}
}
class Podcast implements ContentPrototype {
constructor(
public title: string,
public host: string,
public episodes: number,
public tags: string[],
public publishDate: Date
) {}
clone(): Podcast {
return new Podcast(this.title, this.host, this.episodes, [...this.tags], new Date(this.publishDate.getTime()));
}
display(): void {
console.log(`Podcast Title: ${this.title}`);
console.log(`Host: ${this.host}`);
console.log(`Episodes: ${this.episodes}`);
console.log(`Tags: ${this.tags.join(", ")}`);
console.log(`Publish Date: ${this.publishDate}`);
}
}
Step 3: Use the Prototype Pattern
Let's use these content types and demonstrate cloning in the CMS.
// Creating an original article
const originalArticle = new Article(
"Prototype Pattern in TypeScript",
"This article explains the Prototype Pattern in TypeScript with examples.",
"Bilel Salem",
["design patterns", "typescript"],
new Date()
);
const clonedArticle = originalArticle.clone();
originalArticle.display();
clonedArticle.display();
// Modifying cloned article
clonedArticle.title = "Cloned Article: Prototype Pattern in TypeScript";
clonedArticle.display();
// Creating an original video
const originalVideo = new Video(
"Prototype Pattern Tutorial",
"https://example.com/video",
23,
"Bilel Salem",
new Date()
);
const clonedVideo = originalVideo.clone();
originalVideo.display();
clonedVideo.display();
// Modifying cloned video
clonedVideo.title = "Cloned Video: Prototype Pattern Tutorial";
clonedVideo.display();
// Creating an original podcast
const originalPodcast = new Podcast(
"Design Patterns Podcast",
"Foulen ben Foulen",
23,
["design patterns", "software engineering"],
new Date()
);
const clonedPodcast = originalPodcast.clone();
originalPodcast.display();
clonedPodcast.display();
// Modifying cloned podcast
clonedPodcast.title = "Cloned Podcast: Design Patterns";
clonedPodcast.display();
Explanation
-
Defining the Prototype Interface: The
ContentPrototype interface ensures that all content types can be cloned.
-
Creating Concrete Content Classes: The
Article, Video, and Podcast classes implement the ContentPrototype interface. Each class provides its own clone method to create a deep copy of the object.
-
Using the Prototype Pattern: We create original instances of
Article, Video, and Podcast, then clone them. Modifications to the cloned instances do not affect the original instances, demonstrating the effectiveness of the Prototype Pattern.
Conclusion
The Prototype Pattern is particularly useful in scenarios where object creation is complex or resource-intensive.