August 26, 2025

Prototype Design Pattern

Posted on August 26, 2025  •  4 minutes  • 833 words

The Prototype Design Pattern is a creational design pattern that allows creating new objects by copying existing ones (prototypes). Instead of instantiating a new object directly, you clone an existing object, which can be more efficient in terms of performance and flexibility.

YouTube video thumbnail

Why Use the Prototype Pattern?

  • Object Creation is Expensive: When creating a new object is costly in terms of resources (e.g., database queries, complex initialization).
  • Unknown Object Types at Runtime: When you don’t know the exact type of object to create until runtime.
  • Decoupling Object Creation from Client Code: The client doesn’t need to know which class is instantiated.

Copy Constructor vs Clone Method

Aspect Copy Constructor Clone Method (Prototype)
Type Knowledge Requires knowing the exact type at compile-time. Works with base class pointers; type is resolved at runtime.
Polymorphism Does not support polymorphic copying by default. Supports polymorphism (virtual clone()).
Extensibility Harder to extend when new derived classes are added. Easily extended – new classes just override clone().
Use Case When type is known. When type is unknown or determined at runtime.

Example with Copy Constructor

#include <iostream>
#include <string>

class Shape {
public:
    std::string color;
    Shape(const std::string& c) : color(c) {}
    Shape(const Shape& other) : color(other.color) {} // Copy constructor
    virtual void draw() const = 0;
};

class Circle : public Shape {
public:
    int radius;
    Circle(const std::string& c, int r) : Shape(c), radius(r) {}
    Circle(const Circle& other) : Shape(other), radius(other.radius) {}
    void draw() const override {
        std::cout << "Drawing Circle with color " << color << " and radius " << radius << "\n";
    }
};

int main() {
    Circle original("Red", 10);
    Circle copy = original; // Using copy constructor
    copy.draw();
    return 0;
}

Problem:

  • Works fine when type is known (Circle).
  • But if we have a Shape*, we cannot copy it polymorphically without knowing the exact type.

Example with Prototype (Clone Method)

#include <iostream>
#include <memory>
#include <string>

class Shape {
public:
    std::string color;
    Shape(const std::string& c) : color(c) {}
    virtual ~Shape() = default;
    virtual std::unique_ptr<Shape> clone() const = 0; // Prototype method
    virtual void draw() const = 0;
};

class Circle : public Shape {
public:
    int radius;
    Circle(const std::string& c, int r) : Shape(c), radius(r) {}
    std::unique_ptr<Shape> clone() const override {
        return std::make_unique<Circle>(*this);
    }
    void draw() const override {
        std::cout << "Drawing Circle with color " << color << " and radius " << radius << "\n";
    }
};

int main() {
    std::unique_ptr<Shape> original = std::make_unique<Circle>("Blue", 20);
    std::unique_ptr<Shape> copy = original->clone(); // Polymorphic cloning
    copy->draw();
    return 0;
}

Advantages:

  • Works with base class pointers (Shape* or std::unique_ptr<Shape>).
  • Allows cloning of objects without knowing their exact type at runtime.

Real-World Analogy

Imagine a resume template: - Instead of writing a resume from scratch, you copy the template and modify details. - Prototype pattern works the same way – you copy an existing object and adjust only the needed fields.

When to Use Prototype Pattern?

  • When object creation is expensive.
  • When the system should be independent of how objects are created.
  • When dealing with objects with many configurations.

The Prototype Design Pattern is a powerful tool in C++ that provides flexibility and efficiency when working with complex object hierarchies. Unlike the copy constructor, the clone() method enables polymorphic copying, making it an ideal choice when working with unknown types at runtime.

Example in Youtube Video

prototype.cpp

#include <iostream>
#include <memory>
#include <vector>
#include <string>

class Document
{
public:
    virtual ~Document() = default;
    virtual void print() const = 0;
    virtual std::unique_ptr<Document> clone() const = 0;
};

class Report : public Document 
{
public:
    Report(const std::string& t) : title(t) {}
    Report(const Report& other) : title(other.title) 
    {
        std::cout << "Report cloned\n";
    }
    std::unique_ptr<Document> clone() const override 
    {
        return std::make_unique<Report>(*this);
    }
    void print() const override 
    {
        std::cout << "Report: " << title << "\n";
    }
private:
    std::string title;
};

class Resume : public Document 
{
public:
    Resume(const std::string& n) : name(n) {}
    Resume(const Resume& other) : name(other.name) 
    {
        std::cout << "Resume cloned\n";
    }
    std::unique_ptr<Document> clone() const override 
    {
        return std::make_unique<Resume>(*this);
    }
    void print() const override 
    {
        std::cout << "Resume of: " << name << "\n";
    }
private:
    std::string name;
};

int main(int argc, char const *argv[])
{
    std::vector<std::unique_ptr<Document>> documents;
    documents.push_back(std::make_unique<Report>("Youtube Report 2025"));
    documents.push_back(std::make_unique<Resume>("Anoop P"));

    std::cout << "\nOriginal documents:\n";
    for (const auto& doc : documents)
    {
        doc->print();
    }


    std::cout << "\nTrying to copy documents:\n";
    std::vector<std::unique_ptr<Document>> copies;
    for (const auto& doc : documents)
    {
        copies.push_back(doc->clone());
    }

    std::cout << "\nCopied documents:\n";
    for (const auto& doc : copies)
    {
        doc->print();
    }

    return 0;
}
Follow me

I work on everything coding and share developer memes