C# Prototype Pattern

Summary: in this tutorial, you’ll learn how to use the C# Prototype pattern to create new objects by cloning existing ones.

Introduction to the C# Prototype Pattern

In C#, classes are blueprints for creating new objects. From classes, you use the new operator to create an object.

The Prototype is a creational design pattern that allows you to create new objects by cloning existing objects. In other words, the Prototype pattern allows you to create new objects from existing ones by cloning them without specifying the exact class of the objects.

The Prototype pattern is proper when you create new objects similar to existing ones but with some differences in their state or behavior.

The Prototype pattern is also helpful for creating a complex object that may incur overhead. So, you want to avoid the complexity and the overhead by cloning an existing object instead of creating a new one from scratch.

To implement the Prototype pattern, you follow these steps:

  • First, define an interface or abstract class that specifies a method for cloning objects.
  • Second, create concrete classes implementing the interface or extending the abstract class. Each concrete class represents a specific object type that you can copy later.

To create a new object, you call the Clone() method on the prototype object first and then modify the properties of the cloned object.

The following UML diagram illustrates how the Prototype pattern works.

C# Prototype Pattern

The Prototype pattern involves the following participants:

  • Prototype: The Prototype can be an interface or an abstract class. The Prototype interface (or abstract class) has the Clone() method that creates a new object from an existing object.
  • ConcretePrototype: This is a concrete class of the Prototype interface. The ConcretePrototype class implements the Clone() method for cloning an object.
  • Client: This is the client code that uses the Prototype interface for creating new objects. The client creates a new object by cloning an existing object and then customizes the cloned object as needed.

C# Prototype pattern example

The following C# program demonstrates how to use the Prototype pattern by creating a Warrior prototype and cloning it to create a new warrior with some differences in its properties:

using static System.Console;

namespace PrototypePattern;

public interface IPrototype<T>
{
    T Clone();
}

public class Warrior : IPrototype<Warrior>
{
    public string Name  {  get; set;  }
    public int Health {  get; set; }
    public int AttackPower {   get; set;  }

    public Warrior(string name, int health, int attackPower)
    {
        Name = name;
        Health = health;
        AttackPower = attackPower;
    }

    public override string ToString() 
        => $"Name: {Name}, Health:{Health}, AttackPower: {AttackPower}";

    public Warrior Clone() => (Warrior)MemberwiseClone();

}

public class Client
{
    public static void Main(string[] args)
    {
        // Create an instance of the Warrior prototype
        var loki = new Warrior("Loki", 100, 20);

        // Clone the Loki warrior to create
        // a new warrior named Thor
        var thor = loki.Clone();
        thor.Name = "Thor";
        thor.Health = 120;

        // Now we have two different warrior objects with
        // similar properties but with some differences
        WriteLine(loki);
        WriteLine(thor);
    }
}Code language: C# (cs)

Output:

Name: Loki, Health:100, AttackPower: 20
Name: Thor, Health:120, AttackPower: 20Code language: plaintext (plaintext)

How it works.

First, define an interface called IPrototype with a generic type parameter T. The Prototype<T> has a method called Clone() that will be implemented by the concrete prototype for cloning an object:

public interface IPrototype<T>
{
    T Clone();
}Code language: C# (cs)

Second, define a concrete class Warrior that implements the IPrototype interface. The Warrior class has three properties Name, Health, and AttackPower. Also, it has a constructor to initialize these properties:

public class Warrior : IPrototype<Warrior>
{
    public string Name  {  get; set;  }
    public int Health {  get; set; }
    public int AttackPower {   get; set;  }

    public Warrior(string name, int health, int attackPower)
    {
        Name = name;
        Health = health;
        AttackPower = attackPower;
    }

    public override string ToString() 
        => $"Name: {Name}, Health:{Health}, AttackPower: {AttackPower}";

    public Warrior Clone() => (Warrior)MemberwiseClone();

}Code language: C# (cs)

The Warrior class overrides the ToString() method to return a string representation of the warrior object.

The Warrior class also implements the Clone() method. The Clone() method uses the MemberwiseClone() method that creates a shallow copy of the Warrior object.

Note that the MemberwiseClone method creates a shallow copy of an object by creating a new object and then copying the nonstatic fields of the object to the new object. If a field is a value type, it performs a bit-by-bit copy of the field. If a field is a reference type, it copies only the reference.

Since the properties of the Warrior class are value types (except for the string, which is a reference type but a special case), the shallow copy is fine in this case.

Third, define the Client class with the Main() method as the main entry point of the program:

public class Client
{
    public static void Main(string[] args)
    {
        // Create an instance of the Warrior prototype
        var loki = new Warrior("Loki", 100, 20);

        // Clone the Loki warrior to create
        // a new warrior named Thor
        var thor = loki.Clone();
        thor.Name = "Thor";
        thor.Health = 120;

        // Now we have two different warrior objects with
        // similar properties but with some differences
        WriteLine(loki);
        WriteLine(thor);
    }
}Code language: C# (cs)

In the Main() method, we create a new instance of the Warrior prototype with the name Loki, health 100, and attack power 20. Then we clone the Loki warrior using the Clone() method to create a new warrior named Thor.

The Thor warrior has the same properties as the Loki warrior, except for the Name and Health properties, which are set to Thor and 120, respectively.

The benefit of using the Prototype pattern is that you can create new warriors with similar properties to an existing one without explicitly specifying the Warrior class. Hence, the Prototype pattern offers flexibility and reduces code duplication.

Summary

  • Use the Prototype pattern to create a new object by cloning an existing one without specifying the objects’ class explicitly.
  • Use the MemberwiseClone method to create a shallow copy of the current object.
Was this tutorial helpful ?