Prototype
Intent
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
Problem
You need to create objects that are similar to existing ones, but creating them from scratch is expensive or complex. You want to avoid a proliferation of subclasses just to configure different initial states.
Real-World Analogy
Think of a photocopier. Instead of filling out a complex form from scratch every time, you fill it out once and then photocopy it whenever you need another one. You can then make small edits on each copy — change the name, update the date — without starting over. The original form is the prototype, and each photocopy is a clone you can customize.
When You Need It
- You’re building a graphic editor where users duplicate shapes (circles, rectangles) and tweak their properties, rather than creating each shape from scratch through a complex setup dialog
- You’re creating game levels with many similar objects (trees, enemies, buildings) that differ slightly — cloning a template is faster than constructing each one individually
- You’re working with objects that are expensive to create (e.g., they require database lookups or network calls during initialization) and you need multiple similar instances
UML Class Diagram
classDiagram
class Prototype {
<<interface>>
+clone() Prototype
}
class ConcretePrototypeA {
-fieldA: string
+clone() Prototype
}
class ConcretePrototypeB {
-fieldB: int
+clone() Prototype
}
class Client {
-prototype: Prototype
+operation()
}
Prototype <|.. ConcretePrototypeA
Prototype <|.. ConcretePrototypeB
Client o-- Prototype
Sequence Diagram
sequenceDiagram
participant Client
participant Prototype
participant ConcretePrototype
Client->>Prototype: clone()
Prototype->>ConcretePrototype: create copy
ConcretePrototype-->>Client: cloned object
Participants
| Participant | Role |
|---|---|
| Prototype | Declares an interface for cloning itself |
| ConcretePrototype | Implements the cloning operation |
| Client | Creates a new object by asking a prototype to clone itself |
How It Works
- The Prototype interface declares a
clone()method. - ConcretePrototype implements
clone()by copying its own fields into a new instance. - The Client requests a clone from the prototype instead of calling a constructor.
- The clone is a new, independent object with the same state as the original.
Applicability
Use when:
- A system should be independent of how its products are created, composed, and represented
- Classes to instantiate are specified at runtime (e.g., dynamic loading)
- You want to avoid building a class hierarchy of factories that parallels the class hierarchy of products
Don’t use when:
- Objects are simple and cheap to create from scratch
- Deep cloning is complex and error-prone for your domain
Trade-offs
Pros:
- Avoids the cost of creating objects from scratch when initialization is expensive
- Reduces subclassing — clone and modify instead of creating new subclasses for variants
- Lets you add and remove objects at runtime by registering prototypes
Cons:
- Deep cloning complex objects with circular references can be tricky and error-prone
- Every class that can be cloned needs to implement the clone method
- Cloned objects may share hidden references if deep copy isn’t handled correctly
Example Code
C#
public interface IShape
{
IShape Clone();
void Draw();
}
public class Circle : IShape
{
public int Radius { get; set; }
public string Color { get; set; }
public Circle(int radius, string color)
{
Radius = radius;
Color = color;
}
public IShape Clone() => new Circle(Radius, Color);
public void Draw() => Console.WriteLine($"Circle: radius={Radius}, color={Color}");
}
public class Rectangle : IShape
{
public int Width { get; set; }
public int Height { get; set; }
public Rectangle(int width, int height)
{
Width = width;
Height = height;
}
public IShape Clone() => new Rectangle(Width, Height);
public void Draw() => Console.WriteLine($"Rectangle: {Width}x{Height}");
}
Delphi
type
IShape = interface
function Clone: IShape;
procedure Draw;
end;
TCircle = class(TInterfacedObject, IShape)
private
FRadius: Integer;
FColor: string;
public
constructor Create(ARadius: Integer; const AColor: string);
function Clone: IShape;
procedure Draw;
end;
TRectangle = class(TInterfacedObject, IShape)
private
FWidth, FHeight: Integer;
public
constructor Create(AWidth, AHeight: Integer);
function Clone: IShape;
procedure Draw;
end;
constructor TCircle.Create(ARadius: Integer; const AColor: string);
begin
FRadius := ARadius;
FColor := AColor;
end;
function TCircle.Clone: IShape;
begin Result := TCircle.Create(FRadius, FColor); end;
procedure TCircle.Draw;
begin WriteLn(Format('Circle: radius=%d, color=%s', [FRadius, FColor])); end;
constructor TRectangle.Create(AWidth, AHeight: Integer);
begin
FWidth := AWidth;
FHeight := AHeight;
end;
function TRectangle.Clone: IShape;
begin Result := TRectangle.Create(FWidth, FHeight); end;
procedure TRectangle.Draw;
begin WriteLn(Format('Rectangle: %dx%d', [FWidth, FHeight])); end;
C++
#include <iostream>
#include <memory>
#include <string>
class IShape {
public:
virtual ~IShape() = default;
virtual std::unique_ptr<IShape> clone() const = 0;
virtual void draw() const = 0;
};
class Circle : public IShape {
int radius_;
std::string color_;
public:
Circle(int radius, std::string color)
: radius_(radius), color_(std::move(color)) {}
std::unique_ptr<IShape> clone() const override {
return std::make_unique<Circle>(radius_, color_);
}
void draw() const override {
std::cout << "Circle: radius=" << radius_
<< ", color=" << color_ << "\n";
}
};
class Rectangle : public IShape {
int width_, height_;
public:
Rectangle(int w, int h) : width_(w), height_(h) {}
std::unique_ptr<IShape> clone() const override {
return std::make_unique<Rectangle>(width_, height_);
}
void draw() const override {
std::cout << "Rectangle: " << width_ << "x" << height_ << "\n";
}
};
Runnable Examples
| Language | Source |
|---|---|
| C# | Prototype.cs |
| C++ | prototype.cpp |
| Delphi | prototype.pas |
Related Patterns
- Abstract Factory — can use Prototype to create products
- Composite — designs that make heavy use of Composite often benefit from Prototype
- Decorator — can benefit from Prototype when you need to clone decorated objects