DEV Community

Spyros Ponaris
Spyros Ponaris

Posted on

Prototype Design Pattern in C#: Cloning Objects Efficiently

Introduction

The Prototype Design Pattern is a creational design pattern that allows new objects to be created by copying an existing object (called a prototype) instead of creating them from scratch.

This pattern is particularly useful when:

  • Object creation is expensive or complex.
  • Many similar objects need to be created.
  • You want to avoid repeatedly initializing the same data.

Instead of using constructors every time, the application clones an existing object and modifies only the necessary properties.


Understanding the Prototype Pattern

The Prototype pattern works around a simple idea:

"Create new objects by cloning existing objects."

A prototype object acts as a template. When a new object is needed, the application copies the prototype and customizes it.

Structure

The following class diagram illustrates the Prototype Pattern:

Components:

  1. Prototype (BasicCar)
  • Declares a cloning method.
  • Defines the common interface for cloning.
  1. Concrete Prototypes (Nano, Ford)
  • Implement the cloning operation.
  • Return copies of themselves.
  1. Client (Program)
  • Uses prototypes to create new objects.

Prototype Pattern Example in C

Abstract Prototype

public abstract class BasicCar
{
    public string ModelName { get; set; }
    public int Price { get; set; }

    public static int SetPrice()
    {
        int price = 0;
        Random r = new Random();
        int p = r.Next(200000, 500000);

        price = p;
        return price;
    }

    public abstract BasicCar Clone();
}
Enter fullscreen mode Exit fullscreen mode

Explanation

BasicCar acts as the prototype base class.

It contains:

  • Common properties (ModelName, Price)
  • A utility method for generating random prices
  • An abstract Clone() method that subclasses must implement

Concrete Prototype: Ford

public class Ford : BasicCar
{
    public Ford(string m)
    {
        ModelName = m;
    }

    public override BasicCar Clone()
    {
        return (Ford)this.MemberwiseClone();
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

The Ford class inherits from BasicCar and implements the cloning logic.

return (Ford)this.MemberwiseClone();
Enter fullscreen mode Exit fullscreen mode

This creates a copy of the current object using the built-in MemberwiseClone() method.


Client Code

Console.WriteLine("***Prototype Pattern Demo***\n");

// Base or Original Copy
BasicCar nano_base = new Nano("Green Nano")
{
    Price = 100000
};

BasicCar ford_base = new Ford("Ford Yellow")
{
    Price = 500000
};

BasicCar bc1;

// Nano Clone
bc1 = nano_base.Clone();
bc1.Price = nano_base.Price + BasicCar.SetPrice();

Console.WriteLine(
    "Car is: {0}, and it's price is Rs. {1}",
    bc1.ModelName,
    bc1.Price);

// Ford Clone
bc1 = ford_base.Clone();
bc1.Price = ford_base.Price + BasicCar.SetPrice();

Console.WriteLine(
    "Car is: {0}, and it's price is Rs. {1}",
    bc1.ModelName,
    bc1.Price);

Console.ReadLine();
Enter fullscreen mode Exit fullscreen mode

How the Program Works

Step 1: Create Prototype Objects

BasicCar nano_base = new Nano("Green Nano");
BasicCar ford_base = new Ford("Ford Yellow");
Enter fullscreen mode Exit fullscreen mode

These objects become the prototypes.


Step 2: Clone Instead of Creating

bc1 = nano_base.Clone();
Enter fullscreen mode Exit fullscreen mode

Rather than creating a new Nano, we copy the existing one.


Step 3: Customize the Clone

bc1.Price = nano_base.Price + BasicCar.SetPrice();
Enter fullscreen mode Exit fullscreen mode

The cloned object receives a different price while keeping the original model information.


Step 4: Repeat for Other Car Types

bc1 = ford_base.Clone();
Enter fullscreen mode Exit fullscreen mode

The same cloning mechanism works for any prototype implementation.


Understanding MemberwiseClone()

The Prototype pattern in C# often relies on:

this.MemberwiseClone();
Enter fullscreen mode Exit fullscreen mode

MemberwiseClone() is a protected method of System.Object.

It creates a shallow copy of the current object.

var copy = this.MemberwiseClone();
Enter fullscreen mode Exit fullscreen mode

What Gets Copied?

Value Types

int
bool
double
struct
Enter fullscreen mode Exit fullscreen mode

These are copied by value.

Original ----> 100
Clone    ----> 100
Enter fullscreen mode Exit fullscreen mode

Changes to one do not affect the other.


Reference Types

List<string>
Address
Customer
Array
Enter fullscreen mode Exit fullscreen mode

Only the reference is copied.

Original ---> Address Object
Clone ------^
Enter fullscreen mode Exit fullscreen mode

Both objects point to the same instance.


Shallow Copy vs Deep Copy

The following comparison summarizes the difference:

Type Meaning
Shallow Copy Copies fields, but references stay shared
Deep Copy Creates completely independent copies of all nested objects

Shallow Copy

public Person Clone()
{
    return (Person)this.MemberwiseClone();
}
Enter fullscreen mode Exit fullscreen mode

Result:

Person A ---> Address
Person B ---^
Enter fullscreen mode Exit fullscreen mode

Both persons share the same address object.


Deep Copy

public Person DeepClone()
{
    var copy = (Person)this.MemberwiseClone();

    copy.Address = new Address
    {
        City = this.Address.City
    };

    return copy;
}
Enter fullscreen mode Exit fullscreen mode

Result:

Person A ---> Address A
Person B ---> Address B
Enter fullscreen mode Exit fullscreen mode

Now each object has its own independent nested objects.


Is MemberwiseClone() Safe?

Yes, when:

  • Objects contain only value types.
  • Shared references are acceptable.
  • You manually clone reference-type members afterward.

Be Careful When:

  • Objects contain collections.
  • Objects contain nested objects.
  • Complete independence is required.

In those situations, implement a deep clone.


Benefits of the Prototype Pattern

1. Faster Object Creation

Cloning is often faster than constructing and initializing complex objects.

2. Reduces Repeated Initialization

Objects with many properties can be copied rather than rebuilt.

3. Simplifies Object Creation

Clients don't need to know all construction details.

4. Supports Runtime Object Creation

New objects can be created dynamically from existing prototypes.


Drawbacks

1. Deep Cloning Can Be Complex

Nested object graphs require extra cloning logic.

2. Shared References Can Cause Bugs

Using shallow copies incorrectly may lead to unexpected side effects.

3. Maintenance Overhead

Every new field may require updates to deep-cloning logic.


When Should You Use the Prototype Pattern?

Use Prototype when:

✅ Object creation is expensive

✅ Many similar objects are required

✅ Initialization logic is complex

✅ You need runtime object duplication

Examples include:

  • Game character templates
  • Vehicle configurations
  • Document templates
  • UI component libraries
  • Product catalogs

Conclusion

The Prototype Design Pattern is a powerful creational pattern that creates new objects by cloning existing ones. In C#, it is commonly implemented using MemberwiseClone(), which provides a fast and efficient way to perform shallow copies.

For simple objects, shallow cloning is often sufficient. However, when objects contain nested reference types, a deep clone should be implemented to ensure complete independence between the original object and its clone.

In the car example, Nano and Ford act as concrete prototypes, while BasicCar defines the cloning contract. The client can create new car instances efficiently by cloning existing prototypes instead of constructing them from scratch.

Top comments (0)