Prototype Pattern | Creational design pattern

Prototype Pattern 

The Prototype Pattern is a creational design pattern that deals with object creation by copying an existing object, known as the prototypeInstead of creating an object from scratch, you create new instances by copying an existing object, which serves as a prototype.

Key components and steps involved in the Prototype Pattern:

Prototype Interface/Abstract Class: Defines the methods for cloning itself. This interface or abstract class declares a method like clone().

Concrete Prototype: Implements the cloning method declared in the prototype interface. Objects of this class will be used as prototypes for cloning.

Client: Requests object creation by cloning the prototype. It interacts with the prototype to create new instances.

Advantages:

Reducing subclassing: It allows creating new objects by copying an existing one, eliminating the need for subclassing.

Dynamic object creation: Objects can be created dynamically at runtime based on client requirements.

Customization: The pattern allows creating variations of objects by modifying their cloned copies.

The Prototype Pattern promotes flexibility in object creation by using existing objects as prototypes, facilitating the creation of new instances through cloning.

________
using System;

// Step 1: Prototype Interface
interface ICloneableShape
{
    ICloneableShape Clone();
    void Draw();
}

// Step 2: Concrete Prototype
class Circle : ICloneableShape
{
    private int radius;

    public Circle(int radius)
    {
        this.radius = radius;
    }

    public ICloneableShape Clone()
    {
        // Create a new Circle by copying the current instance
        return new Circle(this.radius);
    }

    public void Draw()
    {
        Console.WriteLine($"Drawing a circle with radius {radius}");
    }
}

// Step 3: Client
class Client
{
    static void Main()
    {
        // Creating a prototype circle
        Circle originalCircle = new Circle(5);

        // Cloning the original circle to create a new one
        Circle clonedCircle = (Circle)originalCircle.Clone();

        // Drawing both circles
        Console.WriteLine("Original Circle:");
        originalCircle.Draw();

        Console.WriteLine("Cloned Circle:");
        clonedCircle.Draw();
    }
}
________

In this example, ICloneableShape is the prototype interface, Circle is the concrete prototype implementing the interface, and the Client demonstrates how to clone a circle and use the cloned object. The Clone method creates a new instance of the Circle class, copying the radius from the original instance.

The Prototype Pattern can be categorized into two main types:

1. Shallow Copy Prototype:
   - In a shallow copy, the cloning process duplicates only the immediate properties of the object, not the objects referenced by the properties.
   - If the object contains references to other objects, the references are copied, but not the actual objects. Both the original and the clone share references to the same objects.
   - Shallow copy is simpler to implement but may lead to unexpected behavior if the referenced objects are mutable.

2. Deep Copy Prototype:
   - In a deep copy, the cloning process creates copies of both the object and all the objects referenced by it, recursively.
   - This ensures that the cloned object is fully independent of the original, and changes made to the original or clone do not affect each other.
   - Deep copy is more complex to implement, especially when dealing with complex object graphs, but it provides a more robust and independent copy.

 Shallow copy is often sufficient when dealing with immutable or simple objects, while deep copy is more suitable when dealing with complex, mutable objects or object graphs.


Real-world use case of a shallow copy often occurs in scenarios where objects have simple, immutable properties, and creating a new instance with the same property values is sufficient. 

Here's an example related to a configuration or settings object:

Suppose you have a Configuration class representing various settings for an application:

________
public class Configuration
{
    public string ApplicationName { get; set; }
    public int MaxConnections { get; set; }
    // Other configuration properties...
}
________

Now, imagine you have a default configuration that you want to use as a template for creating variations with slight modifications. In this case, a shallow copy can be suitable:

________
public class ConfigurationManager
{
    private Configuration defaultConfig;

    public ConfigurationManager(Configuration defaultConfig)
    {
        this.defaultConfig = defaultConfig;
    }

    public Configuration CreateModifiedConfiguration(string appName, int maxConnections)
    {
        // Shallow copy the default configuration
        Configuration modifiedConfig = (Configuration)defaultConfig.Clone();

        // Modify specific properties
        modifiedConfig.ApplicationName = appName;
        modifiedConfig.MaxConnections = maxConnections;

        return modifiedConfig;
    }
}
________

In this example, the CreateModifiedConfiguration method creates a new configuration by performing a shallow copy of the default configuration and then applying modifications to certain properties. This allows you to efficiently generate new configurations based on an existing template without the need to deep copy the entire object, which might be unnecessary for simple and immutable properties.




A deep copy involves creating a new object and then recursively copying all the objects referenced by the original object. Unlike a shallow copy, a deep copy ensures that the cloned object and all of its referenced objects are entirely independent of the original ones. This approach prevents changes in one object from affecting the other.

Example demonstrating a deep copy using serialization :


________
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

// Step 1: Prototype Interface
interface ICloneableShape
{
    ICloneableShape Clone();
    void Draw();
}

// Step 2: Concrete Prototype
[Serializable]
class Circle : ICloneableShape
{
    private int radius;

    public Circle(int radius)
    {
        this.radius = radius;
    }

    public ICloneableShape Clone()
    {
        // Deep copy using serialization
        using (MemoryStream memoryStream = new MemoryStream())
        {
            IFormatter formatter = new BinaryFormatter();
            formatter.Serialize(memoryStream, this);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return (ICloneableShape)formatter.Deserialize(memoryStream);
        }
    }

    public void Draw()
    {
        Console.WriteLine($"Drawing a circle with radius {radius}");
    }
}

// Step 3: Client
class Client
{
    static void Main()
    {
        // Creating a prototype circle
        Circle originalCircle = new Circle(5);

        // Deep copying the original circle to create a new one
        Circle clonedCircle = (Circle)originalCircle.Clone();

        // Drawing both circles
        Console.WriteLine("Original Circle:");
        originalCircle.Draw();

        Console.WriteLine("Cloned Circle:");
        clonedCircle.Draw();

        // Modifying the cloned circle's radius to demonstrate deep copy independence
        clonedCircle.Draw();
    }
}
________

In this example, the Circle class is marked as [Serializable], and the deep copy is implemented using serialization. The Clone method serializes the object to a memory stream and then deserializes it, creating an entirely independent copy of the original object and its referenced objects.



Real-world example of deep copy often arises when dealing with complex objects that have mutable properties and references to other objects. 

Consider a scenario involving a Document class with various sections and styles:

________
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

// Step 1: Prototype Interface
interface ICloneableDocument
{
    ICloneableDocument Clone();
    void Display();
}

// Step 2: Concrete Prototype
[Serializable]
class Document : ICloneableDocument
{
    public string Title { get; set; }
    public List<string> Sections { get; set; }
    public Style DocumentStyle { get; set; }

    public Document(string title, List<string> sections, Style documentStyle)
    {
        Title = title;
        Sections = sections;
        DocumentStyle = documentStyle;
    }

    public ICloneableDocument Clone()
    {
        // Deep copy using serialization
        using (MemoryStream memoryStream = new MemoryStream())
        {
            IFormatter formatter = new BinaryFormatter();
            formatter.Serialize(memoryStream, this);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return (ICloneableDocument)formatter.Deserialize(memoryStream);
        }
    }

    public void Display()
    {
        Console.WriteLine($"Title: {Title}");
        Console.WriteLine("Sections:");
        foreach (var section in Sections)
        {
            Console.WriteLine($"- {section}");
        }
        Console.WriteLine($"Document Style: {DocumentStyle}");
    }
}

// Style class (for simplicity)
[Serializable]
class Style
{
    public string Font { get; set; }
    public string Color { get; set; }

    public Style(string font, string color)
    {
        Font = font;
        Color = color;
    }

    public override string ToString()
    {
        return $"Font: {Font}, Color: {Color}";
    }
}

// Step 3: Client
class Client
{
    static void Main()
    {
        // Creating a prototype document
        Document originalDocument = new Document("Sample Document", new List<string> { "Introduction", "Conclusion" }, new Style("Arial", "Black"));

        // Deep copying the original document to create a new one
        Document clonedDocument = (Document)originalDocument.Clone();

        // Modifying the cloned document to demonstrate deep copy independence
        clonedDocument.Title = "Cloned Document";
        clonedDocument.Sections.Add("Appendix");
        clonedDocument.DocumentStyle.Color = "Blue";

        // Displaying both documents
        Console.WriteLine("Original Document:");
        originalDocument.Display();

        Console.WriteLine("\nCloned Document:");
        clonedDocument.Display();
    }
}
________

In this example, the Document class has mutable properties and contains a reference to the Style class. The Clone method of Document ensures a deep copy by using serialization to create an independent copy of the original document and its referenced Style. This way, modifications to the cloned document do not affect the original, and vice versa.



Comments