Creational Design Patterns - Part 5 - Prototype Patterrn

Deep Dive: Prototype Pattern in C#

Deep Dive: The Prototype Pattern

Creating New Objects by Copying.

What is the Prototype Pattern?

The Prototype is a creational design pattern that lets you create new objects by copying an existing object, known as the "prototype." It allows you to produce a copy of an object without being coupled to its concrete class. This is especially useful when the cost of creating an object from scratch is expensive (e.g., requires a database query, a network call, or complex computation). Instead of rebuilding the object, you simply "clone" a pre-configured instance.

Pros

  • Allows you to clone objects without coupling to their concrete classes.
  • Can be more efficient than creating a complex object from scratch.
  • Removes repetitive initialization code.

Cons

  • Cloning complex objects that have circular references can be very tricky.
  • Requires careful implementation of a deep copy to avoid unintended side effects.

Use Case: Templating Recurring Payment Transactions

The Problem

In a subscription-based service, you need to process thousands of recurring payments every month. Each payment transaction is a complex object containing the amount, currency, merchant details, customer information, billing address, and product ID. For a single customer's subscription, most of these details are identical every month. Creating a new `PaymentTransaction` object from scratch each time would be inefficient, potentially requiring multiple database lookups to fetch all the necessary details again and again.

The Solution

The Prototype pattern is ideal here. We can create a fully configured `PaymentTransaction` object once, when the subscription is first set up, and store it as a prototype. For each subsequent monthly payment, we simply `Clone()` this prototype. The new cloned object will have all the details pre-filled. We only need to update the few fields that change, like the `TransactionId` and `TransactionDate`. This avoids expensive re-creation and ensures consistency.

Visualizing Shallow vs. Deep Copy

Crucial Concept: Shallow vs. Deep Copy

The effectiveness of the Prototype pattern hinges on how you implement the clone. This is the most important detail to get right.

Shallow Copy

Copies only the top-level fields. If a field is a value type (like `int` or `decimal`), its value is copied. If a field is a reference type (like another object or an array), only the reference (memory address) is copied, not the object itself. Both the original and the clone will point to the exact same referenced object.

Danger: Modifying the referenced object in the clone will also modify it for the original prototype!

Deep Copy

Copies everything. It creates a new instance of the object and then, recursively, creates new instances of all objects referenced within it. The original and the clone are completely independent.

Best Practice: For the Prototype pattern to be safe and effective, you almost always need a deep copy.

C# Implementation with Deep & Shallow Copy

Here is a C# implementation for a clonable `PaymentTransaction`. We will implement both a shallow and a deep copy to demonstrate the difference in code.

using System.Text.Json;

// --- 1. The Product and its dependencies ---
public class CustomerDetails { /* ... */ }

public abstract class PaymentTransactionPrototype
{
    public decimal Amount { get; set; }
    public CustomerDetails Customer { get; set; }

    public abstract PaymentTransactionPrototype Clone(bool deep = true);
}

public class PaymentTransaction : PaymentTransactionPrototype
{
    public Guid TransactionId { get; set; }
    public DateTime TransactionDate { get; set; }
    
    public override PaymentTransactionPrototype Clone(bool deep = true)
    {
        if (deep)
        {
            // Deep Copy using serialization
            var serialized = JsonSerializer.Serialize(this);
            return JsonSerializer.Deserialize<PaymentTransaction>(serialized);
        }
        else
        {
            // Shallow Copy using MemberwiseClone
            return (PaymentTransactionPrototype)this.MemberwiseClone();
        }
    }
}

// --- 3. Prototype Registry (Optional, but useful) ---
public class TransactionPrototypes
{
    private readonly Dictionary<string, PaymentTransactionPrototype> _prototypes = new();

    public void Add(string key, PaymentTransactionPrototype prototype) => _prototypes[key] = prototype;
    public PaymentTransactionPrototype Get(string key, bool deep = true) => _prototypes[key].Clone(deep);
}

Prerequisite C# Topics to Understand

Reference Types vs. Value Types
Understanding this is fundamental to grasping shallow vs. deep copy. Classes are reference types; structs and primitive types (int, bool, etc.) are value types. Copying a reference type just copies the memory address, while copying a value type copies the actual value.
`Object.MemberwiseClone()`
This is a protected method on the base `object` class in C#. It creates a shallow copy of the object. It's a quick way to implement shallow cloning, but you must be aware of its limitations.
`ICloneable` Interface
C# has a built-in `ICloneable` interface with a single `Clone()` method. However, it is generally not recommended for modern use because it doesn't specify whether the clone should be shallow or deep, leading to ambiguity. It's better to create your own cloning method with a clear name, like `DeepClone()`.

Comments

Popular posts from this blog

Master Asp.Net Core Middleware concepts.

ASP.net Interview P1

Book Store Project