Categories: Design Pattern

Creational Patterns – Prototype

Prototype – A fully initialized instance to be copied or cloned.

From Design Patterns – Introduction

Structure

Prototype Class Diagram UML

Applicability

When the source code shouldn’t depend on the object’s class, you need to use this pattern to copy.

Reduce the number of the subclasses which only differ in initializing their respective objects.

Pros and Cons

PRONS

  • Clone objects and without coupling to their concrete classes.
  • The flavor of clone object pre-building prototype and do not need to without the initialization class code.
  • Easy to make the complex object by clone pre-building model methods.
  • Use the inheritance methods when the code configuration presets the complex objects.

CONS

  • The Clone complex objects that have re-circular reference characters, which maybe is very involved.

How to Implement

#1 Basic Sample

public class Demo
{
 public int ID { get; set; } = 1;
 public string Name { get; set; } = string.Empty;
 public IdInfo IdInfo;

 public Demo ShallowCopy()
 {
  return (Demo)this.MemberwiseClone();
 }

 public Demo DeepCopy()
 {
  Demo clone = (Demo)this.MemberwiseClone();
  clone.IdInfo = new IdInfo(IdInfo.IdNumber);
  clone.Name = String.Copy(Name);
  return clone;
 }
}

public class IdInfo
{
 public Guid IdNumber;

 public IdInfo(Guid _IdNumber) => IdNumber = _IdNumber;
}

class Program
{
 static void Main(string[] args)
 {
  Demo p1 = new Demo
  {
   Name = "Jack",
   IdInfo = new IdInfo(Guid.NewGuid())
  };

  // Perform a shallow copy of p1 and assign it to p2.
  Demo p2 = p1.ShallowCopy();
  // Make a deep copy of p1 and assign it to p3.
  Demo p3 = p1.DeepCopy();

  // Display values of p1, p2 and p3.
  Console.WriteLine("Original values of p1, p2, p3:");
  Console.WriteLine("   p1 instance values: ");
  Console.WriteLine(" ID: {0}, Name: {1},GUID: {2}",
   p1.ID, p1.Name, p1.IdInfo.IdNumber.ToString());
  Console.WriteLine("   p2 instance values:");
  Console.WriteLine(" ID: {0}, Name: {1},GUID: {2}",
   p2.ID, p2.Name, p2.IdInfo.IdNumber.ToString());
  Console.WriteLine("   p3 instance values:");
  Console.WriteLine(" ID: {0}, Name: {1},GUID: {2}",
   p3.ID, p3.Name, p3.IdInfo.IdNumber.ToString());

  p1.Name = "Frank";
  p1.IdInfo.IdNumber = Guid.NewGuid();
  Console.WriteLine("\nValues of p1, p2 and p3 after changes to p1:");
  Console.WriteLine("   p1 instance values: ");
  Console.WriteLine(" ID: {0}, Name: {1},GUID: {2}",
   p1.ID, p1.Name, p1.IdInfo.IdNumber.ToString());
  Console.WriteLine("   p2 instance values (reference values have changed):");
  Console.WriteLine(" ID: {0}, Name: {1},GUID: {2}",
   p2.ID, p2.Name, p2.IdInfo.IdNumber.ToString());
  Console.WriteLine("   p3 instance values (everything was kept the same):");
  Console.WriteLine(" ID: {0}, Name: {1},GUID: {2}",
   p3.ID, p3.Name, p3.IdInfo.IdNumber.ToString());

  Console.ReadKey();
 }
}

#2 Web Application Project

Step 1 Create the generic repository class mechanism for the prototype patterns. The interface class name sets “IPrototype.” The generic repository class name sets “PrototypeRepo.” One method that can affect operation is a GET method, which works to get a single data function. This method name sets “Prototype_GetById.”

The IPrototype class file source code shows below:

public interface IPrototype<T> where T : class
{
 T Prototype_GetById(int id);
}

The statement the variable of the IGenericTypeRepository class in the PrototypeRepo class. The Prototype_GetById method uses the IGenericTypeRepository variable to call the GetById method of GenericTypeRepository and return T.

The PrototypeRepo class file source code shows below:

public class PrototypeRepo<T> : IPrototype<T> where T : class
{
 private IGenericTypeRepository<T> repo;


 public PrototypeRepo(IGenericTypeRepository<T> _repo)
 {
  this.repo = _repo;
 }

 public T Prototype_GetById(int id) => repo.GetById(id).Result as T; 
} 

Step 2 Create a new entity model class under the Core project for the prototype patterns to create. The new entity model class file name sets “PrototypeEntity.”

The PrototypeEntity class file source code shows below:

public class PrototypeEntity
{
 public int ID { get; set; }

 public string Name { get; set; }

 public int? Age { get; set; }

 public IdInfo IdInfo;

 public PrototypeEntity ShallowCopy()
 {
  return (PrototypeEntity)this.MemberwiseClone();
 }

 public PrototypeEntity DeepCopy()
 {
  PrototypeEntity clone = (PrototypeEntity)this.MemberwiseClone();
  clone.IdInfo = new IdInfo(IdInfo.IdNumber);
  return clone;
 }
}

public class IdInfo
{
 public Guid IdNumber;

 public IdInfo(Guid _IdNumber) => IdNumber = _IdNumber;
}

Note: In the prototype class diagram UML picture, you can find an IdInfo class object in the PrototypeEntity class to statement. I short the code and write it in the same class file because I want the reader to read these elements easily.

Step 3 Create a controller file and view files under the web project. The controller file name sets “PrototypeController.” The view part creates the Index page.

Fig 1 Web project solution explorer – Prototype patterns

Step 4 Call a single data by IPrototype class, then layout the result by ViewData method. After calling single information, the entity model object re-sets the object’s value, such as the new GUID, the name field, then puts the result to the Tuple object.

The Index page source code of the PrototypeController file shows below:

public IActionResult Index()
{
    var PrototypeObj = repo.Prototype_GetById(1);
    PrototypeEntity prototypeEntity = new PrototypeEntity()
    {
 ID = PrototypeObj.ID,
 Name = PrototypeObj.Name,
 Age = PrototypeObj.Age,
 IdInfo = new IdInfo(Guid.NewGuid())
    };

    PrototypeEntity prototypeEntity2 = prototypeEntity.ShallowCopy();
    PrototypeEntity prototypeEntity3 = prototypeEntity.DeepCopy();

    Tuple<PrototypeEntity, PrototypeEntity, PrototypeEntity> Result_tuple = 
 new Tuple<PrototypeEntity, PrototypeEntity, PrototypeEntity>(prototypeEntity, prototypeEntity2, prototypeEntity3);

    // Before
    // prototypeEntity object
    ViewData["Item1_ID"] = prototypeEntity.ID;
    ViewData["Item1_Name"] = prototypeEntity.Name;
    ViewData["Item1_Age"] = prototypeEntity.Age;
    ViewData["Item1_Guid"] = prototypeEntity.IdInfo.IdNumber;
    // prototypeEntity2 object
    ViewData["Item2_ID"] = prototypeEntity2.ID;
    ViewData["Item2_Name"] = prototypeEntity2.Name;
    ViewData["Item2_Age"] = prototypeEntity2.Age;
    ViewData["Item2_Guid"] = prototypeEntity2.IdInfo.IdNumber;
    // prototypeEntity3 object
    ViewData["Item3_ID"] = prototypeEntity3.ID;
    ViewData["Item3_Name"] = prototypeEntity3.Name;
    ViewData["Item3_Age"] = prototypeEntity3.Age;
    ViewData["Item3_Guid"] = prototypeEntity3.IdInfo.IdNumber;
    // After
    prototypeEntity.Name = "After_Changed_Nmae";
    prototypeEntity.IdInfo.IdNumber = Guid.NewGuid();

    return View(Result_tuple);
}

Reference

davidsky69

Recent Posts

API Gateway in .NET 5 with Ocelot

What is the API gateway? An API gateway is an API management tool that sits…

3 years ago

.NET 5 application with Onion architecture

The .NET 5 SDK is a kind of milestone in the .NET world. The .NET…

4 years ago

SOLID Principles – Dependency inversion principle

In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software…

4 years ago

SOLID Principles – Interface segregation principle

In the field of software engineering, the interface segregation principle (ISP) states that no code…

4 years ago

SOLID Principles – Liskov substitution principle

Subtype Requirement: Let  be a property provable about objects  of type T. Then  should be true for objects  of type S where S is…

4 years ago

SOLID Principles – Open-closed principle

In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be…

4 years ago