Prototype Pattern

Hello everyone, and welcome to .NET Core Central. In this blog post, I am going to walk through the Prototype Pattern.

So what is a Prototype design pattern? The Prototype design pattern is also a creational design pattern just like the Builder pattern, the Abstract Factory design pattern, and the Factory Method design pattern.

What is Prototype Pattern?

The Prototype design pattern is a pattern we will use while creating a new object from an existing type. The main intent of this pattern is to allow us to create copies of an already created object.

The question we need to ask is why we will ever need this kind of pattern? When we need to create an object, we can just go ahead and create a new object using the new keyword. Or we can get it from a dependency injection container.

When using a dependency injection container, we are just going to ask the dependency injection container to give us a new object. If we register the object as a transient object, every time we ask the dependency injection container to give us the object it will give us a new object.

Why do we need the Prototype Pattern?

Well, there is one scenario where we might need to use something like a prototype pattern. The situation where we need to create a copy from an existing instance and we want to copy the exact state of the instance.

And in which scenarios do we need to do that? Let us consider a scenario where we are creating a very complex object. Whose state is created out of some database call or some HTTP call.

In that case, it is not wise to make the same database call or HTTP call every time we want to create the object. In fact, it will be much cheaper if we can just clone an existing object. And then just use all the state of the object as is into a new instance.

Now the other question you might ask is, well in that case also we can just inject the existing object and create a new object of the same type. And then just set the properties from the existing object to the new object and we should be good.

The use case for Prototype Pattern

Well, that does not work in every scenario. For example, let us take the case of this IUser, which is implemented by this User class. For the purpose of this application, I will use Visual Studio 2022 with .NET 6 and C# 10.

namespace PrototypePattern.Demo;

public interface IUser
{
    string Name { get; }
    string Address { get; }
    int Age { set; }
}

public class User : IUser
{
    private string name;
    private int age;
    private string address;

    public User(string name, string address)
    {
        this.name = name;
        this.address = address;
    }

    public string Name => name;

    public string Address => address;

    public string Details => $"User : {name}, Age: {age}, Address: {address}";

    public int Age
    {
        set { age = value; }
    }
}

Now if we want to clone the User class, we are going to face a hurdle. The Name and Address are getter-only properties, which should not cause any issues. But Age is a setter-only property. Meaning the private variable age which is part of this User class’s state, can never be set from outside the class. Because we don’t have access to this private variable so we cannot set it outside.

Problem with clone the traditional way

Let us consider the scenario where we are going to create a clone of the User object ourselves. To achieve that, we will create a new REST API controller class UserController. And we will inject the IUser interface into this API.

Firstly, we will configure the IUser as a part of the dependency injection container. And we will provide a name and address during the construction of the User object. We will set the Age property separately.

using PrototypePattern.Demo;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var user = new User("Name", "Address");
user.Age = 20;
builder.Services.AddSingleton<IUser>(user);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Secondly, we will create the UserController class. And in this class, we will try to create a clone from the injected IUser instance. But for cloning, we will create a new instance of the User object using the injected IUser.

using Microsoft.AspNetCore.Mvc;

namespace PrototypePattern.Demo.Controllers;
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
    private readonly IUser user;

    public UserController(IUser user)
    {
        this.user = new User(user.Name, user.Address);
    }

    [HttpGet]
    public IUser Get() => user;
}

In this case, we created a clone of the User object with the name and address. But we can never set the value of Age.

Hence when we access the user object, the Age is always going to be zero. If we run the application, we will see the Details property of the User object will have 0 as Age.

prototype pattern

And this is the problem with this type of cloning implementation. So to solve that we use the Prototype Design Pattern.

The Implementation

Now how do we implement the prototype pattern? Thankfully in C# language and the .NET Framework (5,6)/Core, even legacy .NET has an interface called IClonable.

When we implement IClonable, it comes with a Clone method. The Clone method returns an object.

For our example, we will derive the IUser interface from the IClonable interface. That will give the User class the Clone method.

namespace PrototypePattern.Demo;

public interface IUser : ICloneable
{
    string Name { get; }
    string Address { get; }
    int Age { set; }
}

public class User : IUser
{
    private string name;
    private int age;
    private string address;

    public User(string name, string address)
    {
        this.name = name;
        this.address = address;
    }

    public string Name => name;

    public string Address => address;

    public string Details => $"User : {name}, Age: {age}, Address: {address}";

    public int Age
    {
        set { age = value; }
    }

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

For the implementation of the Clone method, we will return the output from the MemberwiseClone method on the current instance. The MemberwiseClone method is part of the base object class. And it creates a shallow copy of the object.

Update to controller

Now, we will update the UserController class. And in the constructor of the class, we will call the Clone method of the user object.

using Microsoft.AspNetCore.Mvc;

namespace PrototypePattern.Demo.Controllers;
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
    private readonly IUser user;

    public UserController(IUser user)
    {
        this.user = user.Clone() as IUser;
    }

    [HttpGet]
    public IUser Get() => user;
}

At this point, if we run the application, we will see the Age value 20 is getting reflected in the Details property of the user object.

Conclusion

The Prototype design pattern is a very useful pattern in scenarios where the creation of an object is expensive. And as you can see it is very easy to do on the .NET platform.

So this covers how you can use the Prototype pattern to build an expensive object.

A Youtube video for this implementation is here.