Back to: Design Patterns in C# With Real-Time Examples
Prototype Design Pattern in C# with Examples
In this article, I will discuss the Prototype Design Pattern in C# with Examples. Please read our previous article discussing the Fluent Interface Design Pattern in C# with Examples. The Prototype Design Pattern falls under the category of the Creational Design Pattern.
What is the Prototype Design Pattern?
As per the GoF Definition, “Prototype Design Pattern specifies the kind of objects to create using a prototypical instance, and create new objects by copying this prototype“.
To simplify the above definition, we can say that the Prototype Design Pattern gives us a way to create new or cloned objects from the existing object of a class. That means it clones the existing object with its data into a new object. If we make any changes to the cloned object (i.e., new object), it does not affect the original object.
The Prototype design pattern refers to creating duplicate objects while keeping performance in mind. This pattern involves implementing a prototype interface to create a clone of the current object. This pattern is used when the creation of an object is costly and resource-intensive.
Note: The Prototype Design Pattern is unique among the other Creational Design Patterns as it doesn’t require a class; instead, it requires an object.
Example to Understand Prototype Design Pattern in C#:
Let us understand the Prototype Design Pattern in C# with an example. In C#, when we try to copy one object to another using the assignment (=) operator, both objects share the same memory address. The reason is the assignment operator (=) copies the reference, not the object, except when there is a value type field. This operator will always copy the reference, not the actual object, when working with the Reference type. Please have a look at the following image for a better understanding.
As you can see in the above image, we have one class called Employee, having two properties, i.e., Name and Department. Within the Main method, first, we create an instance of the Employee class (i.e., emp1) and set values for Name and Department properties. Then, we create another employee instance (i.e., emp2) by assigning the existing employee object (i.e., emp1). When we change the Name property value of the emp2 object, it also changes the name of the emp1 object, and this is because both emp1 and emp2 share the same memory. So, remember that when we use the assignment (=) operator, it is Call-By-Reference only. The Complete Examples Code is given below.
using System; namespace PrototypeDesignPattern { class Program { static void Main(string[] args) { // Creating an Instance of Employee Class Employee emp1 = new Employee(); emp1.Name = "Anurag"; emp1.Department = "IT"; // Creating another Instance of Employee with Existing Employee Instance using Assignment Operator // Both emp1 and emp2 share the same memory location as = Operator uses Call By Reference Mechanism Employee emp2 = emp1; // Changing the Name Property Value of emp2 instance, // it will also change the Name Property Value of emp1 instance emp2.Name = "Pranaya"; Console.WriteLine("Emplpyee 1: "); Console.WriteLine("Name: " + emp1.Name + ", Department: " + emp1.Department); Console.WriteLine("Emplpyee 2: "); Console.WriteLine("Name: " + emp2.Name + ", Department: " + emp2.Department); Console.Read(); } } public class Employee { public string Name { get; set; } public string Department { get; set; } } }
Output:
What is Object Cloning in C#?
When we talk about Object Cloning in C#, it means it is all about the Call By Value. So, if we change one object, it will not affect the other. Let us see how to clone the object to another object. To do so, C# provides one method called MemberwiseClone, which will create a new complete copy of the object having a different memory. For a better understanding, please have a look at the below image.
As shown in the above image, within the Employee class, we created one method, i.e., GetClone. As part of that method, we return a clone object using the MemberwiseClone method. Then, from the client code, we create a new instance of the Employee class and assign the properties with some values. Next, we create the second object by calling the GetClone method, which returns a new complete copy of the emp1 object. Now, both the objects (i.e., emp1 and emp2) are independent, and if we make any changes to any object, it will not affect other objects.
Note: Remember that the MemberwiseClone() method creates a shallow copy of the object. If your object contains other objects and you want a deep copy where even those internal objects are duplicated, you’d need to implement custom logic in the Clone() method. In our next article, we will discuss shallow and deep copies in detail.
Example to Understand Object Cloning in C#
The following code example shows how to create a Duplicate or Cloned Object from an Existing object using Object Cloning. The following example code is self-explained, so please go through the comment lines for a better understanding.
using System; namespace PrototypeDesignPattern { class Program { static void Main(string[] args) { // Creating an Instance of Employee Class Employee emp1 = new Employee(); emp1.Name = "Anurag"; emp1.Department = "IT"; // Instead of using Assignment Operator, now use the Clone method to create a Cloned Object // Both emp1 and emp2 having different Memory Address Employee emp2 = emp1.GetClone(); // Changing the Name Property Value of emp2 instance, // will not change the Name Property Value of emp1 instance emp2.Name = "Pranaya"; Console.WriteLine("Emplpyee 1: "); Console.WriteLine("Name: " + emp1.Name + ", Department: " + emp1.Department); Console.WriteLine("Emplpyee 2: "); Console.WriteLine("Name: " + emp2.Name + ", Department: " + emp2.Department); Console.Read(); } } public class Employee { public string Name { get; set; } public string Department { get; set; } public Employee GetClone() { // MemberwiseClone Method Creates a shallow copy of the current System.Object // So typecast the Object Appropriate Type // In this case, typecast to Employee type return (Employee)this.MemberwiseClone(); } } }
Output:
Points to Remember about MemberwiseClone Method in C#:
- The MemberwiseClone method is part of the System.Object class and creates a shallow copy of the given object.
- MemberwiseClone Method only copies the non-static fields of the object to the new object.
- In copying, if a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied, but the referenced object is not.
So, once we have understood Object Cloning, let us proceed further and understand how to implement Prototype Design Patterns in C# using Object Cloning.
Real-Time Example to Understand Prototype Design Patterns in C#:
As we discussed, the Prototype Design Pattern in C# is used when we want to create a Duplicate or Cloned Object from an Existing object to enhance the application’s performance. That means we need to use this Prototype Design Pattern when creating an object is costly and complex. For Example, if you want to create an object after a costly database operation. Then, in that case, we can cache the object, return its clone on the next request, and update the database as and when needed, reducing the database interaction with our application. As a result, the performance will be improved.
Let us proceed and implement the Prototype Design Pattern in C# step by step. Once we implement the Prototype Design Pattern, we will see the UML Diagram and compare the Example with the Prototype Design Pattern UML (or Class) Diagram. So, first, create a class file with the name Employee.cs and then copy and paste the following code into it. The following class is the Prototype Abstract Class, which is used for the types of objects that can be cloned.
namespace PrototypeDesignPattern { //The Prototype Abstract Class //This is an abstract class which is used for the types of object that can be cloned itself. public abstract class Employee { public string Name { get; set; } public string Department { get; set; } public string Type { get; set; } public abstract Employee GetClone(); public abstract void ShowDetails(); } }
As you can see, the above class has few properties common with the next-level subclasses and two abstract methods that the child classes will implement.
So, next, create a class file with the name PermanentEmployee.cs and then copy and paste the following code into it. Here, you can see that the class implements the Employee abstract class and provides implementations for the two abstract methods. In the GetClone method, we have written the logic to create a shallow copy of the current object. In our next article, we will discuss Shall Copy and Deep Copy in detail. The following code is self-explained, so please go through the comment lines for a better understanding.
using System; namespace PrototypeDesignPattern { //This is a class that implements the Prototype interface for cloning itself. public class PermanentEmployee : Employee { public int Salary { get; set; } public override Employee GetClone() { // MemberwiseClone Method Creates a shallow copy of the current System.Object // So typecast the Object Appropriate Type // In this case, typecast to PermanentEmployee type return (PermanentEmployee)this.MemberwiseClone(); } public override void ShowDetails() { Console.WriteLine("Permanent Employee"); Console.WriteLine($" Name:{this.Name}, Department: {this.Department}, Type:{this.Type}, Salary: {this.Salary}\n"); } } }
Next, create a class file named TemporaryEmployee.cs and copy and paste the following code. Here, you can see the class implements the Employee abstract class and provides implementations for the two abstract methods. In the GetClone method, we have written the logic to create a shallow copy of the current object. The following code is self-explained, so please go through the comment lines for a better understanding.
using System; namespace PrototypeDesignPattern { //This is a class that implements the Prototype interface for cloning itself. public class TemporaryEmployee : Employee { public int FixedAmount { get; set; } public override Employee GetClone() { // MemberwiseClone Method Creates a shallow copy of the current System.Object // So typecast the Object Appropriate Type // In this case, typecast to TemporaryEmployee type return (TemporaryEmployee)this.MemberwiseClone(); } public override void ShowDetails() { Console.WriteLine("Temporary Employee"); Console.WriteLine($" Name:{this.Name}, Department: {this.Department}, Type:{this.Type}, FixedAmount: {this.FixedAmount}\n"); } } }
We need to test whether the Clone Method is working as expected within the Client code. In our example, the Main method of the Program class is nothing but the client. So, please modify the Main method of the Program class as follows. The following example code is self-explained, so please go through the comment lines for a better understanding.
using System; namespace PrototypeDesignPattern { class Program { static void Main(string[] args) { // Creating an Instance of Permanent Employee Class Employee emp1 = new PermanentEmployee() { Name = "Anurag", Department = "IT", Type = "Permanent", Salary = 100000 }; //Creating a Clone of the above Permanent Employee Employee emp2 = emp1.GetClone(); // Changing the Name and Department Property Value of emp2 instance, // will not change the Name and Department Property Value of the emp1 instance emp2.Name = "Pranaya"; emp2.Department = "HR"; emp1.ShowDetails(); emp2.ShowDetails(); // Creating an Instance of Temporary Employee Class Employee emp3 = new TemporaryEmployee() { Name = "Preety", Department = "HR", Type = "Temporary", FixedAmount = 200000 }; //Creating a Clone of the above Temporary Employee Employee emp4 = emp3.GetClone(); // Changing the Name and Department Property Value of emp4 instance, // will not change the Name and Department Property Value of the emp3 instance emp4.Name = "Priyanka"; emp4.Department = "Sales"; emp3.ShowDetails(); emp4.ShowDetails(); Console.Read(); } } }
Output:
Prototype Design Pattern UML (Class) Diagram:
Once we understand how to implement the Prototype Design Pattern in C#, let us try to understand the UML (Unified Modeling Language) or Class diagram of the Prototype Design Pattern. For a better understanding, please look at the following diagram, which shows the different components of the Prototype Design Pattern. Here, I am comparing the Prototype Design Pattern UML diagram with our example so that you can easily understand the different components of the Prototype Design Pattern.
Let us understand each component of the Prototype Design Pattern:
- Prototype: This will be an interface or abstract class used for the types of objects that can be cloned. In our example, it is going to be the Employee Abstract Class.
- ConcretePrototype: This class will implement the Prototype abstract class or interface for cloning. In our example, it will be the PermanetEmployee and TemporaryEmployee Classes.
- Client: The client is the class that creates a new object by asking a prototype to clone itself.
When to use Prototype Design Pattern in C#?
The Prototype design pattern is used to instantiate a new object by copying existing objects, known as prototypes. It can be beneficial in several scenarios:
- Performance Concerns: When creating an instance of an object is more expensive than copying an existing one. This could be due to memory allocation, computation, or initialization steps.
- Unique Instances with Shared Data: When you need distinct instances but a significant amount of shared data, the Prototype pattern can be efficient. Instead of recreating that shared data for each instance, you can clone an existing prototype.
- Dynamic Configuration: When the classes to instantiate are specified at runtime or through configuration, not compile-time.
- Avoid Subclassing: In some scenarios, instead of subclassing a class to create variations, it’s easier to replicate (or clone) an instance and set its varying properties.
- Complex Object Creation: When an object has many shared configurations and only a few differences, it’s easier to clone a pre-configured object and adjust the differences than to build from scratch.
- Maintain Object State: If you need a replica of an object in a specific state rather than an object with default settings.
- Working with Immutable Objects: When dealing with objects that shouldn’t be altered after construction. Instead of modifying them, you clone a copy and change the new instance.
- Decouple from Class Definition: If you want to keep your system decoupled from its classes’ static methods, then the Prototype pattern can help. This pattern uses an instance-specific clone method.
Considerations:
- Shallow vs. Deep Copy: The built-in MemberwiseClone in C# creates a shallow copy. If your object graph contains complex or nested objects and you need a deep copy, you must implement this yourself. This is a critical aspect to consider when using the Prototype pattern.
- Modification Side Effects: Be cautious of unexpected side effects. Modifying reference objects in the cloned object will also modify the original if you use shallow copying.
- Initialization: If the object requires special initialization steps that cloning might bypass, ensure the clone is still valid or consistent after its creation.
Real-Time Applications of the Prototype Design Pattern in C#
The Prototype Design Pattern revolves around creating a clone or a copy of an existing object rather than creating a new instance from scratch. The pattern is particularly useful when creating a new instance is more time or resource-intensive than copying an existing one. Here are some real-time applications of the Prototype pattern in C#:
- Graphics and Game Development: In graphics and game development, often, objects like shapes, textures, or game entities can be cloned from a prototype rather than being loaded or recreated from scratch. This can speed up rendering and in-game instantiation.
- Cache Mechanism: The Prototype can be useful for caching objects. Instead of re-fetching data and creating a new object, the application can return a cloned object from the cache.
- Undo/Redo in Applications: The Prototype pattern can be used in applications where undo and redo functionalities are needed (like graphic editors or word processors). A cloned object representing the current state is saved whenever a change is made. If the user decides to undo it, the application can revert to the previous state using the saved prototype.
- Database Record Duplication: In applications that involve database operations, sometimes a record needs to be duplicated with slight modifications. Instead of manually setting all properties, an object representing the record can be cloned and modified as required.
- Load Balancing: In distributed systems, objects can be cloned and sent to different servers for parallel processing to reduce the load on a single server.
- Runtime Object Duplication in IDEs: Integrated Development Environments (IDEs) might allow users to copy an entire object or component at runtime and then paste or use it as a separate instance. This is especially common in UI design tools, where you can duplicate UI components.
- Objects with Dynamic Configurations: If an object has configurations computed at runtime and you need multiple instances with similar configurations, it might be easier to clone a prototype than to recompute configurations for each new instance.
- Testing and Mocking: The Prototype pattern can be handy in automated tests, especially when using mock objects. Instead of setting up a new mock for each test, a pre-configured mock can be cloned and used, ensuring isolation between tests.
- Load Testing: When simulating multiple users or operations for load testing, rather than creating unique objects for each simulated operation, clones of a prototype can be used, saving on setup time and resources.
Remember, while the Prototype pattern can be very useful in these scenarios, deciding between a shallow copy (where the cloned object still references the same sub-objects as the original) and a deep copy (where all sub-objects are also cloned) is crucial. Depending on the application, one might be more appropriate than the other.
In summary, the Prototype pattern is ideal when object creation is costly or complex, and you’d rather duplicate an existing object than instantiate a new one from scratch. Before using this pattern, assess the implications of shallow versus deep cloning for your specific scenario.
While working with object cloning, we need to understand two things, i.e., Shallow Copy and Deep Copy. So, in the next article, I will discuss the Shallow Copy and Deep Copy in C# with Examples. In this article, I try to explain the Prototype Design Pattern in C# with Examples. I hope you understand the need and use of the Prototype Design Pattern in C# with Examples.
We also create second objet by using new keyword then why we use this pattern
If you create the 2nd object by using new keyword, then you need to reassign the respective (same) values. No need for clone. it is cloning.
https://learn.microsoft.com/en-us/dotnet/api/system.object.memberwiseclone?view=net-7.0 says memberwiseclone is giving a shallow copy.
Yes. Please check the next article where the author explain how to implement deep copy.
How relevant is it to clone an object in the place of creation through any other Pattern ? Cloning will lead to performance degradation if it concerns the creation of a large number of small objects ????