PrototypePattern-原型模式
在C#中,原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过克隆现有对象来创建新对象,而无需依赖于显式的构造函数。原型模式通过复制现有对象的属性和状态,创建一个新对象,并在需要创建对象时返回这个克隆的副本。
原型模式的核心是使用原型接口或基类来定义克隆方法,并让具体类实现该方法来实现克隆功能。在C#中,原型模式的实现方式可以使用对象的MemberwiseClone()
方法或序列化和反序列化来实现。
原型模式的意义在于对象的复用,减小对象构建对资源的开销
1.单例原型
单例模式:保证整个进程中,该对象只有一个实例
public class StudentSingleton
{
public int Id { get; set; }
public string Name { get; set; }
/// <summary>
/// 构造函数私有化
/// </summary>
private StudentSingleton()
{
Console.WriteLine("{0}被构造..", this.GetType().Name);
}
/// <summary>
/// 静态字段
/// </summary>
private static StudentSingleton _Student = new StudentSingleton()
{
Id = 001,
Name = "小明"
};
/// <summary>
/// 开放的静态方法获取实例
/// </summary>
/// <returns></returns>
public static StudentSingleton CreateInstance()
{
return _Student;
}
public void Study()
{
Console.WriteLine("{0}正在学习", this.Name);
}
}
internal class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
StudentSingleton student = StudentSingleton.CreateInstance();
student.Study();
}
//输出结果
//StudentSingleton被构造..
//小明正在学习
//小明正在学习
//小明正在学习
}
}
扩展:C#内存分配机制
C#中的内存分配面向对象,对于值类型(如int、float)和引用类型(如string、类)的内存分配方式有所不同
int
的内存分配:int
是值类型,它的值直接存储在栈上。当声明一个 int
变量时,分配的内存空间大致等于一个 int
的大小(通常为4字节)。
string
的内存分配:string
是引用类型,它的实例存储在托管堆(Managed Heap)上。当使用 new
关键字创建一个 string
对象时,会在堆上分配一块内存空间来存储字符串的值。
{
Console.WriteLine("***************Singleton**************");
StudentSingleton student1 = StudentSingleton.CreateInstance();
StudentSingleton student2 = StudentSingleton.CreateInstance();
student1.Id = 002;
student1.Name = "小红";
student2.Id = 003;
student2.Name = "小黄";
Console.WriteLine(student1.Id);
Console.WriteLine(student1.Name);
Console.WriteLine(student2.Id);
Console.WriteLine(student2.Name);
//输出结果
//3
//小黄
//3
//小黄
}
单例模式整个进程只有一个实例,在C#内存分配机制中student1与student2属于引用类型,指向堆的同一块区域。所以后面的会覆盖前面的。
2.拷贝原型
MemberwiseClone()
方法:内存拷贝,不走构造函数,直接内存copy,所以没有性能损失;
public class Classroom
{
public int ClassroomId { get; set; }
public string ClassroomName { get; set; }
}
public class StudentPrototype
{
public int Id { get; set; }
public string Name { get; set; }
public Classroom classroom { get; set; }
/// <summary>
/// 构造函数私有化
/// </summary>
private StudentPrototype()
{
Console.WriteLine("{0}被构造..", this.GetType().Name);
}
/// <summary>
/// 静态字段
/// </summary>
private static StudentPrototype _Student = new StudentPrototype()
{
Id = 001,
Name = "小明",
classroom = new Classroom()
{
ClassroomId = 1,
ClassroomName = "小学"
}
};
/// <summary>
/// 开放的静态方法获取实例
/// </summary>
/// <returns></returns>
public static StudentPrototype CreateInstance()
{
StudentPrototype student = (StudentPrototype)_Student.MemberwiseClone();
return student;
}
public void Study()
{
Console.WriteLine("{0}{1}正在{2}号{3}学习", this.Name, this.Id, this.classroom.ClassroomId, this.classroom.ClassroomName);
}
}
{
Console.WriteLine("***************Prototype**************");
StudentPrototype student1 = StudentPrototype.CreateInstance();
StudentPrototype student2 = StudentPrototype.CreateInstance();
StudentPrototype student3 = StudentPrototype.CreateInstance();
student1.Id = 002;
student1.Name = "小红";
student1.classroom.ClassroomId = 2;
student1.classroom.ClassroomName = "初中";
//因为string类型的 ="CodeMan" 等同于 new String("CodeMan"); 开辟新的空间,不影响之前的-----实际上string是不可修改的----
student2.Id = 003;
student2.Name = "小黄";
student2.classroom.ClassroomId = 3;
student2.classroom.ClassroomName = "高中";
student3.Id = 004;
student3.Name = "小蓝";
student3.classroom = new Classroom()
{
ClassroomId = 4,
ClassroomName = "大学"
};
student1.Study();
student2.Study();
student3.Study();
//输出结果
//StudentPrototype被构造..
//小红2正在3号高中学习
//小黄3正在3号高中学习
//小蓝4正在4号大学学习
}
student1与student2的classroom属性属于引用类型,MemberwiseClone()
方法属于浅拷贝,只拷贝classroom属性的引用地址。
StudentPrototype中的Name属性也属于引用类型(string),但student1.Name = "小红"等同于student1.Name = new String("小红"),这是String类型的特性,每次重新赋值只会重新开辟一块新的空间。
student3的classroom属性把引用的地址重新赋值,完成了深拷贝——不仅拷贝引用,还得拷贝引用类型的值。
原型模式(Prototype Pattern)是一种创建型设计模式,它通过克隆现有对象来创建新对象,而不是通过使用构造函数创建。原型模式具有以下优点和缺点:
优点:
-
对象克隆:原型模式允许通过复制现有对象来创建新对象。这避免了使用构造函数创建对象的复杂性,并提供了一种更简单、更高效的对象创建方法。
-
减少对象创建的开销:通过原型模式,可以避免重复创建相似的对象,并且可以在需要大量相似对象时,通过克隆现有对象来节省创建的开销。
-
隐藏创建细节:原型模式可以将对象创建的细节隐藏在后台,对客户端来说,只需要关心如何获取和使用克隆对象。
-
动态增加和替换对象:原型模式支持动态地增加和替换对象,通过修改原型对象,可以在运行时改变某些属性或行为,从而获得新的对象。
缺点:
-
对象克隆过程复杂:如果对象的拷贝过程比较复杂,包含深层次的嵌套对象或引用对象,那么实现对象的克隆可能会比较困难。
-
需要实现Clone方法:为了使用原型模式,需要在每个可克隆的类中实现Clone方法。这增加了代码的维护和管理的复杂性。
-
克隆与构造函数不同:对象克隆是通过复制现有对象来创建新对象,与使用构造函数创建对象的方式有所不同。这可能会引起一些设计上的困惑和问题。
需要根据具体的应用场景和需求来评估使用原型模式的利弊。原型模式适用于需要根据现有对象创建新对象的情况,通过克隆提供了更高效、更简单的对象创建方法。通过权衡其优点和缺点,可以选择是否使用原型模式。