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.

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*
orstd::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;
}