Understanding the Prototype Pattern

bilel salem - Jun 27 - - Dev Community

ASSALAMUALAIKUM WARAHMATULLAHI WABARAKATUH, السلام عليكم و رحمة اللّه و بركاته

Introduction

Design patterns are essential in software engineering as they provide time-tested solutions to common problems. One such pattern is the Prototype Pattern, which can simplify the process of creating new objects. In this article, we will explore the Prototype Pattern, understand its usages, and see how to implement it in TypeScript with some real-world examples.

What is the Prototype Pattern?

The Prototype Pattern is a creational design pattern that allows you to clone existing objects instead of creating new instances from scratch. This is particularly useful when object creation is costly or complex.

Key Concepts

  • Prototype: The original object that you want to clone.
  • Cloning: Creating a new object that is a copy of the prototype.

Why Use the Prototype Pattern?

  1. Performance: Cloning an object can be faster than creating a new instance.
  2. Complexity: Simplifies the creation of objects with complex configurations.
  3. Flexibility: Allows you to create new objects without knowing the exact class of the object that will be created.

Implementing the Prototype Pattern in TypeScript

Let's look at how to implement the Prototype Pattern in TypeScript. We'll start with a simple example and then move to more complex examples.

Simple Example

First, let's define an interface for cloning.

interface Prototype {
    clone(): Prototype;
}
Enter fullscreen mode Exit fullscreen mode

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}`);
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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}`);
    }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Explanation

  1. Defining the Prototype Interface: The ContentPrototype interface ensures that all content types can be cloned.
  2. 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.
  3. 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.

. . . . . . . . . . . . . . . . . . . . . . .