This is the 10th day of my participation in the August More text Challenge. For details, see: August More Text Challenge
Prototype pattern: Creating customizable objects from one object without knowing any of the details of the creation.
Characters in archetypal mode:
Abstract Prototype: provides a clone interface
Concrete Prototype: and the implementation of the clone interface Concrete Prototype class
Requirements for a prototype pattern:
Override the Clone method in the abstract class or override the Clone method in ICloneable.
In other words: to implement the Clone class, you must implement its Clone method.
No more nonsense: The above example, HERE I refer to the resume in the “design pattern” :
First, normal to achieve:
Resume: Resume. Cs
using System;
namespace Prototypes
{
public class Resume
{
/// <summary>
///The name
/// </summary>
public string name;
/// <summary>
///gender
/// </summary>
public string sex;
/// <summary>
///The name
/// </summary>
public string age;
/// <summary>
///Working time
/// </summary>
public string timeArea;
/// <summary>
///The name of the company
/// </summary>
public string company;
/// <summary>
///The constructor
/// </summary>
public Resume(string name)
{
this.name = name;
}
/// <summary>
///Setting personal Information
/// </summary>
public void SetPersonalInformation(string age,string sex)
{
this.age = age;
this.sex = sex;
}
/// <summary>
///Setting work experience
/// </summary>
public void SetWorkExperience(string timeArea, string company)
{
this.timeArea = timeArea;
this.company = company;
}
public void Show()
{
// Output personal information
Console.WriteLine(name+""+age+""+sex);
// Output work experience
Console.WriteLine("Work Experience :"+timeArea+""+company); }}}Copy the code
The client Program. Cs
using System;
namespace Prototypes
{
class Program
{
static void Main(string[] args)
{
Resume one = new Resume("camellia");
one.SetPersonalInformation("23"."Male");
one.SetWorkExperience("1999-2005"."Pilot Technology");
one.Show();
Console.WriteLine("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
Resume two = new Resume("camellia");
two.SetPersonalInformation("23"."Male");
two.SetWorkExperience("2005-2008"."Enlightenment technology"); two.Show(); Console.ReadKey(); }}}Copy the code
If it needs to be changed, it needs to be changed a lot.
Let’s use the prototype pattern to implement this example:
Cloning can be divided into shallow replication and deep replication.
Shallow copy: Copy all the fields in the original object to a new object one by one. If the fields are of value type, then simply copy a copy to the new object. Changing the value type of the fields in the new object does not affect the original object. If the field is of reference type, then the reference is copied, and changing the value of the field of reference type in the target object will affect the original object. For example, if an object has a field that points to a reference type (such as work experience in our example), and we make a shallow copy of the object, then both objects will refer to the same reference (that is, the same work experience).
The code I’m testing here uses C# : C# provides a method MemberwiseClone() without our shallow copy; The method works like this: if the field is of value type, copy it directly; if the field is of reference type, copy the reference, but do not copy the referenced object. This is something to be aware of.
The above code: shallow copy
Resume: Resumeqian.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prototypes
{
/// <summary>
///Resume class with ICloneable interface (shallow copy)
/// </summary>
public class ResumeQian : ICloneable
{
public ResumeQian()
{
mWorkExperience = new WorkExperienceQian();
}
private string mName;
private string mSex;
private int mAge;
private WorkExperienceQian mWorkExperience;
public string Name
{
get { return mName; }
set { mName = value; }}public string Sex
{
get { return mSex; }
set { mSex = value; }}public int Age
{
get { return mAge; }
set { mAge = value; }}/// <summary>
///A reference type is associated
/// </summary>
public WorkExperienceQian WorkExperience
{
get { returnmWorkExperience; }}public void SetWorkExperience(DateTime startDate, DateTime endDate, string company, string position)
{
this.mWorkExperience.Company = company;
this.mWorkExperience.EndDate = endDate;
this.mWorkExperience.StartDate = startDate;
this.mWorkExperience.Position = position;
}
/// <summary>
///Show your work experience
/// </summary>
public void Show()
{
Console.WriteLine("Company:" + this.mWorkExperience.Company);
Console.WriteLine("End time:" + this.mWorkExperience.EndDate);
Console.WriteLine("Start time:" + this.mWorkExperience.StartDate);
Console.WriteLine("Location:" + this.mWorkExperience.Position);
Console.WriteLine("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
}
/// <summary>
///Implement the Clone method of the ICloneable interface
/// </summary>
/// <returns></returns>
public object Clone()
{
//.net provides us with a shallow copy of the object method
return this.MemberwiseClone(); }}}Copy the code
Work experience: workexperienceqian.cs (reference type)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prototypes
{
/// <summary>
///Work Experience Class (shallow copy)
/// </summary>
public class WorkExperienceQian
{
public DateTime StartDate;
public DateTime EndDate;
public string Company;
public stringPosition; }} Client call: program.cs console. WriteLine("Shallow copy = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
// Instantiate the resume class
ResumeQian myFirstResume = new ResumeQian
{
Age = 29,
Name = "camellia",
Sex = "Male"};// Set your first job experience
myFirstResume.SetWorkExperience(new DateTime(2006.7.1), new DateTime(2007.7.1), "The first"."Pilot Technology");
// Present the first resume
myFirstResume.Show();
Clone your first resume as your second job experience.
ResumeQian mySecondResume = (ResumeQian)myFirstResume.Clone();
// Set the work experience
mySecondResume.SetWorkExperience(new DateTime(2007.8.1), new DateTime(2008.8.1), "A second"."Enlightenment technology");
// Present the first resume
myFirstResume.Show();
// Present the second resume. This is when you will find a problem. The work experience in the first resume shown here is the same as in the second resume.
// Because we are using a shallow copy here, the work experience is a reference type, so it changes with the changes passed in.
mySecondResume.Show();
ResumeQian myThirdResume = (ResumeQian)myFirstResume.Clone();
mySecondResume.SetWorkExperience(new DateTime(2008.8.1), new DateTime(2009.8.1), "The third"."So technology.");
myFirstResume.Show();
mySecondResume.Show();
mySecondResume.Show();
Copy the code
The output is as shown in the figure below:
If the resume is copied like this, it will be a problem. At this point we use deep copy to achieve resume cloning ~
Deep copy: Different from shallow copy in the handling of reference types, deep copy points the reference type fields in the new object to the new object that has been copied. Changing any object referenced in the new object will not affect the contents of the corresponding fields in the original object. For example, if an object has a field that points to a reference type (such as work experience in the example) and a deep copy is made of the object. I will create a new object (i.e. a new work experience).
Above code: deep copy
The essence of deep replication is to implement the Clone method on objects of reference type. In the class you want to clone, add the class that references the type to it. It’s not very clear, just look at the code.
Resume: resumeshen.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prototypes
{
/// <summary>
///Resume class with ICloneable interface (deep copy)
/// </summary>
public class ResumeShen : ICloneable
{
public ResumeShen()
{
mWorkExperience = new WorkExperienceShen();
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = deep copy key = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/// <summary>
///A private constructor is used here to copy the reference type to which it is connected
/// </summary>
/// <param name="workExperience"></param>
private ResumeShen(WorkExperienceShen workExperience)
{
this.mWorkExperience = (WorkExperienceShen)workExperience.Clone();
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = deep copy key = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
private string mName;
private string mSex;
private int mAge;
private WorkExperienceShen mWorkExperience;
public string Name
{
get { return mName; }
set { mName = value; }}public string Sex
{
get { return mSex; }
set { mSex = value; }}public int Age
{
get { return mAge; }
set { mAge = value; }}public WorkExperienceShen WorkExperience
{
get { returnmWorkExperience; }}/// <summary>
///Set up the achievements and experiences
/// </summary>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <param name="company"></param>
/// <param name="position"></param>
public void SetWorkExperience(DateTime startDate, DateTime endDate, string company, string position)
{
this.mWorkExperience.Company = company;
this.mWorkExperience.EndDate = endDate;
this.mWorkExperience.StartDate = startDate;
this.mWorkExperience.Position = position;
}
public void Show()
{
Console.WriteLine("Company:" + this.mWorkExperience.Company);
Console.WriteLine("End time:" + this.mWorkExperience.EndDate);
Console.WriteLine("Start time:" + this.mWorkExperience.StartDate);
Console.WriteLine("Location:" + this.mWorkExperience.Position);
Console.WriteLine("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
}
/// <summary>
///Implement the Clone method of the ICloneable interface
/// </summary>
/// <returns></returns>
public object Clone()
{
// The MemberwiseClone method is no longer used for replication, but a new resume is created. It's implemented entirely internally, and the outside doesn't care about its implementation
ResumeShen newResume = new ResumeShen(this.mWorkExperience);
newResume.mSex = this.mSex;
newResume.mName = this.mName;
newResume.mAge = this.mAge;
returnnewResume; }}}Copy the code
Work experience class: workExperienceshen. cs also need to implement the Clone method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prototypes
{
public class WorkExperienceShen : ICloneable
{
public DateTime StartDate;
public DateTime EndDate;
public string Company;
public string Position;
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = deep copy key = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
public object Clone()
{
// Use the methods that.NET provides for shallow replication of objects
String is a reference type, but C# has made it special for us to use it like a value type.
return this.MemberwiseClone();
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = deep copy key = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =}}Copy the code
Client call: program.cs
Console.WriteLine("Deep copy = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
ResumeShen myFirstResumeShen = new ResumeShen
{
Age = 29,
Name = "camellia",
Sex = "Male"}; myFirstResumeShen.SetWorkExperience(new DateTime(2006.7.1), new DateTime(2007.7.1), "The first"."Pilot Technology");
myFirstResumeShen.Show();
ResumeShen mySecondResumeShen = (ResumeShen)myFirstResumeShen.Clone();
mySecondResumeShen.SetWorkExperience(new DateTime(2007.8.1), new DateTime(2008.8.1), "A second"."Enlightenment technology");
myFirstResumeShen.Show();
mySecondResumeShen.Show();
ResumeShen myThirdResumeShen = (ResumeShen)myFirstResumeShen.Clone();
myThirdResumeShen.SetWorkExperience(new DateTime(2008.8.1), new DateTime(2009.8.1), "The third"."So technology.");
myFirstResumeShen.Show();
mySecondResumeShen.Show();
myThirdResumeShen.Show();
Copy the code
The realization effect is shown in the figure below:
This is exactly what we want.
At the beginning of this article, I mentioned the necessary conditions for a prototype pattern:
Override the Clone method in the abstract class or override the Clone method in ICloneable.
In the example above, we used the Clone method overwritten in ICloneable. Let’s write a small example that overwrites the Clone method in an abstract class (only shallow copying).
Color class: color.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prototype
{
// ================ Shallow replication =================
public abstract class Colors
{
public int red;
public int blue;
public int black;
public abstract Colors clone();
}
// ================ Shallow replication =================} subclass GetRed. Csusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prototype
{
public class GetRed:Colors
{
public override Colors clone()
{
// MemberwiseClone C# provides us with methods for shallow replication of objects
return (Colors)this.MemberwiseClone(); }}}Copy the code
Client call: program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prototype
{
class Program
{
static void Main(string[] args)
{
// ================ Shallow replication =================
Colors getRed = new GetRed();
getRed.red = 123;
Console.WriteLine("red:"+ getRed.red);
Colors getRedTwo = getRed.clone();
getRedTwo.red = 152;
Console.WriteLine("redtwo:" + getRedTwo.red);
Console.WriteLine("red:" + getRed.red);
// ================ Shallow replication =================Console.ReadLine(); }}}Copy the code
The running results are as follows:
We found that when we changed the value of the Red property of the getRed object, there was no effect on the getRedTwo property.
That is, changes to the copy of the object do not affect the state of the object itself.
It is important to note that the prototype pattern does not have to be overwritten in ICloneable’s Clone method to be implemented.
Finally, let’s summarize the pros and cons of the prototype pattern:
Advantages:
-
Hiding the details of object creation is also a big performance improvement for classes that take a lot of resources to initialize.
-
When you need a new object, you can use Clone to quickly create one instead of building it with new.
Disadvantages:
-
Each class needs a Clone method and must be considered in its entirety.
-
For deep copies, each associated type must implement the IClonable interface, and the Clone method needs to be updated every time a field is added or modified.
Application scenario:
-
Class initialization consumes a large number of resources, including data, hardware resources, and so on
-
Generating an object with new requires a lot of data preparation or access, so you can use the prototype pattern
-
When an object needs to be made available to other objects and each caller may need to modify its value, consider using the prototype pattern to copy multiple objects for the caller to use.
For good suggestions, please enter your comments below. Welcome to guanchao.site
Welcome to applet: