Prototype Design Pattern


Here, we will explain Prototype Design Pattern with example in C#

Prototype Design Pattern Introduction

The Prototype design pattern is a creational pattern that allows you to create new objects by copying an existing object, known as the prototype. This pattern is particularly useful when object creation is costly, and you want to avoid creating objects from scratch. It provides an efficient way to create objects with existing states.

Advantages of the Prototype Pattern

  1. Performance Optimization - Creating new objects by copying existing ones is more efficient than creating objects from scratch, especially when object creation is complex and time-consuming.
  2. Simplified Object Creation - Complex objects can be copied with their internal states intact, saving the need to reinitialize them with detailed logic.
  3. Reduced Subclassing - Prototype avoids the need for subclasses when object configuration and creation vary slightly.
  4. Flexibility - You can add or remove prototypes dynamically at runtime, allowing for more flexible and dynamic applications.
  5. Decoupling - The pattern decouples the client from the object creation process, as the client doesn’t need to know the specific classes being instantiated.

When to Use the Prototype Pattern

  • When Object Creation Is Expensive - If creating a new object is resource-intensive (e.g., involving network calls or complex computations), you can use the prototype pattern to clone an already existing object.
  • When You Want to Avoid Subclassing - Instead of using a subclass for every possible configuration of an object, you can clone a prototype object and customize the clone.
  • When You Need Flexibility - If objects can change their types or structure at runtime, the prototype pattern allows for easy cloning and modification of objects.

Problems in a System Without the Prototype Pattern

  • High Object Creation Cost - Without the prototype pattern, creating many instances of objects that are resource-intensive or involve complex construction logic can slow down performance.
  • Code Duplication -Without this pattern, you may end up writing similar object creation code multiple times, leading to redundancy.
  • Lack of Flexibility - Systems without the prototype pattern might be forced into rigid class hierarchies, making it difficult to change or extend object behavior dynamically.

Real-World Example - Car Manufacturing

A real-world example of the prototype pattern is manufacturing. When a company designs a prototype for a new product (such as a car), the prototype is tested and refined until it meets the standards. Once the design is finalized, the company can create multiple identical units based on that prototype without going through the entire design process again.

Prototype Design Pattern

For instance, when producing a car, the manufacturer creates a prototype. Once the prototype is approved, the same model is produced in bulk by cloning the prototype design.

using System;

// Prototype Interface
public interface ICarPrototype
{
    ICarPrototype Clone();
}

// Concrete Prototype
public class Car : ICarPrototype
{
    public string Model { get; set; }
    public string Color { get; set; }
    public string EngineType { get; set; }

    public Car(string model, string color, string engineType)
    {
        Model = model;
        Color = color;
        EngineType = engineType;
    }

    // Clone method to create a copy of the car
    public ICarPrototype Clone()
    {
        return (ICarPrototype)this.MemberwiseClone();
    }

    public void ShowDetails()
    {
        Console.WriteLine($"Car Model: {Model}, Color: {Color}, Engine: {EngineType}");
    }
}

// Client
class Program
{
    static void Main(string[] args)
    {
        // Create a prototype car
        Car prototypeCar = new Car("Sedan", "Black", "V8");

        // Clone the prototype to create new cars
        Car car1 = (Car)prototypeCar.Clone();
        car1.Color = "Red"; // Customize the cloned car

        Car car2 = (Car)prototypeCar.Clone();
        car2.Color = "Blue"; // Customize the cloned car

        // Display details of the cloned cars
        prototypeCar.ShowDetails(); // Prototype car
        car1.ShowDetails(); // Customized car1
        car2.ShowDetails(); // Customized car2
    }
}

Explanation

  1. ICarPrototype - The interface defines the Clone() method that will be implemented by all concrete classes.
  2. Car - The Car class implements ICarPrototype and provides a cloning mechanism through the Clone() method, which uses the MemberwiseClone() method to create a shallow copy of the object.
  3. Client (Program) - A prototype car is created, and it is cloned to create two additional cars (car1 and car2), which are customized with different colors

Output

Prototype Design Pattern

Example of Graphical Editing Software with the Prototype Pattern

Imagine a graphical editing software where you have various shapes like circles, rectangles, and triangles. Each shape has different properties such as size, color, and position. If the user wants to create multiple copies of a shape, instead of recreating the shape from scratch with the same properties, the application can clone an existing shape (prototype) and modify it if necessary.

using System;
using System.Collections.Generic;

// Prototype Interface
public abstract class Shape
{
    public int X { get; set; }
    public int Y { get; set; }
    public string Color { get; set; }

    // Abstract method for cloning the shape
    public abstract Shape Clone();

    // Display method to show shape information
    public virtual void Display()
    {
        Console.WriteLine($"Shape: {GetType().Name}, X: {X}, Y: {Y}, Color: {Color}");
    }
}

// Concrete Prototype: Circle
public class Circle : Shape
{
    public int Radius { get; set; }

    // Clone method that copies the Circle object
    public override Shape Clone()
    {
        return (Shape)MemberwiseClone();
    }

    // Display additional information about the circle
    public override void Display()
    {
        Console.WriteLine($"Shape: Circle, X: {X}, Y: {Y}, Color: {Color}, Radius: {Radius}");
    }
}

// Concrete Prototype: Rectangle
public class Rectangle : Shape
{
    public int Width { get; set; }
    public int Height { get; set; }

    // Clone method that copies the Rectangle object
    public override Shape Clone()
    {
        return (Shape)MemberwiseClone();
    }

    // Display additional information about the rectangle
    public override void Display()
    {
        Console.WriteLine($"Shape: Rectangle, X: {X}, Y: {Y}, Color: {Color}, Width: {Width}, Height: {Height}");
    }
}

// Concrete Prototype: Triangle
public class Triangle : Shape
{
    public int Base { get; set; }
    public int Height { get; set; }

    // Clone method that copies the Triangle object
    public override Shape Clone()
    {
        return (Shape)MemberwiseClone();
    }

    // Display additional information about the triangle
    public override void Display()
    {
        Console.WriteLine($"Shape: Triangle, X: {X}, Y: {Y}, Color: {Color}, Base: {Base}, Height: {Height}");
    }
}

// Shape Manager to handle prototypes
public class ShapeManager
{
    private Dictionary<string, Shape> _shapes = new Dictionary<string, Shape>();

    // Register a shape prototype
    public void RegisterShape(string key, Shape shape)
    {
        _shapes[key] = shape;
    }

    // Get a cloned shape
    public Shape GetShape(string key)
    {
        if (_shapes.ContainsKey(key))
        {
            return _shapes[key].Clone();
        }
        else
        {
            throw new ArgumentException("Shape not found");
        }
    }
}

public class Program
{
    public static void Main()
    {
        // Create initial shape prototypes
        Circle circle = new Circle { X = 10, Y = 20, Color = "Red", Radius = 15 };
        Rectangle rectangle = new Rectangle { X = 30, Y = 40, Color = "Blue", Width = 100, Height = 50 };
        Triangle triangle = new Triangle { X = 50, Y = 60, Color = "Green", Base = 70, Height = 35 };

        // Shape Manager to store prototypes
        ShapeManager shapeManager = new ShapeManager();
        shapeManager.RegisterShape("circle", circle);
        shapeManager.RegisterShape("rectangle", rectangle);
        shapeManager.RegisterShape("triangle", triangle);

        // Create clones of the shapes
        Shape clonedCircle = shapeManager.GetShape("circle");
        Shape clonedRectangle = shapeManager.GetShape("rectangle");
        Shape clonedTriangle = shapeManager.GetShape("triangle");

        // Modify the cloned shapes
        clonedCircle.X = 100;
        clonedCircle.Y = 200;
        clonedCircle.Color = "Yellow";

        clonedRectangle.X = 300;
        clonedRectangle.Y = 400;
        clonedRectangle.Color = "Purple";

        clonedTriangle.X = 500;
        clonedTriangle.Y = 600;
        clonedTriangle.Color = "Orange";

        // Display the original and cloned shapes
        Console.WriteLine("Original Shapes:");
        circle.Display();
        rectangle.Display();
        triangle.Display();

        Console.WriteLine("\nCloned and Modified Shapes:");
        clonedCircle.Display();
        clonedRectangle.Display();
        clonedTriangle.Display();
    }
}

In the above example, the Circle object can be cloned, making it easy to create similar shapes without reinitializing them.

Explanation

  1. Shape Class (Prototype Interface) - This is the base class that defines common properties like X, Y, and Color for all shapes. It includes the Clone() method which will be overridden in the derived classes.

  2. Concrete Prototype Classes (Circle, Rectangle, Triangle) - These classes inherit from Shape and implement the Clone() method using the MemberwiseClone() method to create shallow copies of objects.

  3. ShapeManager Class - This class acts as a registry to store the original prototypes and allows cloning of the stored shapes by calling their Clone() method.

  4. Main Program

    • It registers some initial shapes (Circle, Rectangle, Triangle) with different properties.
    • Clones these shapes, modifies the properties of the clones, and then displays both the original and cloned shapes.

Outout

Prototype Design Pattern

Applications of the Prototype Design Pattern

  • Game Development: In games, characters, enemies, or objects may have different types but share many common attributes. The prototype pattern allows you to clone existing characters and slightly alter their characteristics.
  • Document or Spreadsheet Applications: When users duplicate existing templates or documents, the application can create a copy (clone) using the prototype pattern.
  • Configuration Management Systems: When setting up environments with complex configurations, a system can use a prototype configuration as a base, making slight adjustments rather than creating everything from scratch.
  • Database Query Result Caching: If results from database queries are stored in memory as objects and reused frequently, they can be cloned using the prototype pattern to avoid querying the database again.

Prev Next

Top Articles

  1. What is JSON
  2. How to convert a javaScript object in JSON object
  3. Some Important JSON Examples
  4. Common JSON Interview Question