Prototype Pattern: Cloning Objects in C#

Introduction

In the previous article, "Builder Pattern: Constructing Complex Objects Step by Step," we learned that design patterns are used to create complex objects step by step. This pattern is especially useful when an object needs to be created with various configurations or when the construction process involves multiple steps.

In this article, we will learn about the prototype pattern. The prototype pattern is a creational design pattern that is used to create new objects by cloning existing objects. This pattern is particularly useful when it requires more resources or when the object contains complex data structures.

Understanding the Prototype Pattern

The Prototype Pattern is a creational design pattern that allows you to create new objects by copying an existing instance (the prototype). Instead of creating an object from scratch, you clone a pre-existing object. This is especially useful when creating new objects that are costly in terms of performance or involve complex configurations.

Instead of creating from scratch, we just create copies of existing objects, which means the original objects are our prototype; using that prototype, we clone the other object, and sometimes, if required, some properties change in the cloned object. So, using this pattern, we saved a lot of time and also hid the complex implementation. They just used the clone() method.

Key Components

  • Prototype Interface: Declares a method that clones objects.
  • Concrete Prototype: Implements the Clone() method to create a copy of the object.
  • Client: Uses the Clone() method to create new objects based on existing ones.

Example in C#

Let's illustrate the Prototype Pattern with a practical example to create different types of shapes by cloning existing shape objects.

1. Define the Prototype Interface

IPrototypeShape.cs

namespace Prototype_Pattern_Demo
{
    public interface IPrototypeShape
    {
        IPrototypeShape Clone();
        void DisplayInfo();
    }
}

Explanation

The IPrototypeShape interface defines the Clone() method that must be implemented by concrete shape classes. The DisplayInfo() method will be used to print details about the shape.

2. Implement the Concrete Prototype (Circle and Rectangle)

Circle.cs

namespace Prototype_Pattern_Demo
{
    public class Circle : IPrototypeShape
    {
        public int Radius { get; set; }
        public Circle(int radius)
        {
            Radius = radius;
        }
        public IPrototypeShape Clone()
        {
            return new Circle(this.Radius);
        }
        public void DisplayInfo()
        {
            Console.WriteLine("Circle with radius: " + Radius);
        }
    }

}

Rectangle.cs

namespace Prototype_Pattern_Demo
{
    public class Rectangle : IPrototypeShape
    {
        public int Width { get; set; }
        public int Height { get; set; }
        public Rectangle(int width, int height)
        {
            Width = width;
            Height = height;
        }
        public IPrototypeShape Clone()
        {
            return new Rectangle(this.Width, this.Height);
        }
        public void DisplayInfo()
        {
            Console.WriteLine("Rectangle with width: " + Width + " and height: " + Height);
        }
    }

}

Explanation

Both Circle and Rectangle implement the IPrototypeShape interface. The Clone() method creates a new instance of the object with the same properties. The DisplayInfo() method is used to display the shape’s dimensions.

3. Using the Prototype in the Client

Program.cs

using Prototype_Pattern_Demo;

class Program
{
    static void Main(string[] args)
    {
        Circle originalCircle = new Circle(10);
        Console.WriteLine("Original Circle : ");
        originalCircle.DisplayInfo();


        Circle clonedCircle = (Circle)originalCircle.Clone();
        Console.WriteLine("Clone Circle : ");
        clonedCircle.DisplayInfo();

        Rectangle originalRectangle = new Rectangle(5, 7);
        Console.WriteLine("Original Rectangle : ");
        originalRectangle.DisplayInfo();

        Rectangle clonedRectangle = (Rectangle)originalRectangle.Clone();
        Console.WriteLine("Clone Rectangle : ");
        clonedRectangle.DisplayInfo();


        clonedCircle.Radius = 15;
        clonedRectangle.Width = 10;
        clonedRectangle.Height = 12;

        Console.WriteLine("\nUpdated cloned shapes:");
        clonedCircle.DisplayInfo();
        clonedRectangle.DisplayInfo();

        Console.WriteLine("\nOriginal shapes remain unchanged:");
        originalCircle.DisplayInfo();
        originalRectangle.DisplayInfo();
    }
}

Explanation

The Program.cs file demonstrates the Prototype Pattern in action. We first create a circle and a rectangle, display their information, clone them, and then modify the cloned objects. Notice that changes to the cloned objects do not affect the original objects, which illustrates the benefit of cloning rather than directly copying references.

Output

Output

Real-World use cases

  • Document Templates: Cloning existing templates to create new documents with the same structure but different content.
  • Game Development: Creating new game entities (e.g., characters, weapons) by cloning pre-configured prototypes.
  • UI Elements: Duplicating pre-existing user interface components and altering them without affecting the original.

Benefits of Singleton Pattern

  • Performance: Cloning existing objects can be much faster than creating new instances from scratch, especially when object creation involves costly operations.
  • Avoid Complex Initializations: The Prototype Pattern simplifies the process of object creation by bypassing complex setup steps that are already part of the original object.
  • Maintains Object Integrity: Ensures that the original object remains unchanged when a new instance is created via cloning.

Summary

The Prototype Pattern provides a flexible and efficient way to create new objects by cloning existing ones. By cloning objects, we avoid the overhead of recreating objects from scratch, especially when the construction process is resource-intensive. In this article, we demonstrated how to use the Prototype Pattern to create shapes in C# and explored its real-world applications and benefits.

Next Steps

In the next article, "Adapter Pattern: Bridging Incompatible Interfaces", we will dive into the Adapter Pattern, which helps bridge the gap between incompatible interfaces, making it easier to integrate different systems or objects in a seamless way. This pattern is often used in legacy code integration and API development, so stay tuned for more insights!


Similar Articles