原型模式(Prototype Pattern)
概念:
是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
优点:
- 性能提高。
- 逃避构造函数的约束。
原型模式的缺点:
- 需要为每一个类都配置一个 clone 方法 clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
- 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
适用场景
多用于创建大对象,或初始化繁琐的对象。如游戏中的背景,地图。
以下场景适用:
- 资源优化场景。
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景。
- 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景。
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
- 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。
浅拷贝和深拷贝
原型模式中的拷贝对象可以分为:“浅拷贝”和“深拷贝”。
浅拷贝:
- 当类的成员变量是基本值数据类型时,浅拷贝会复制该属性的值赋值给新对象。
- 当成员变量是引用数据类型时,浅拷贝复制的是引用数据类型的地址值。这种情况下,当拷贝出的某一个类修改了引用数据类型的成员变量后,会导致所有拷贝出的类都发生改变。
深拷贝:
- 深拷贝不仅会复制成员变量为基本数据类型的值,给新对象。还会给是引用数据类型的成员变量【申请】储存空间,并复制引用数据类型成员变量的对象。 这样拷贝出的新对象就不怕修改了是引用数据类型的成员变量后,对其它拷贝出的对象造成影响了。
/// <summary>
/// 工作信息类
/// </summary>
class 工作信息
{
private int salary;//工资
private string entryTime;//入职时间
public int Salary { get => salary; set => salary = value; }
public string EntryTime { get => entryTime; set => entryTime = value; }
}
using System;
/// <summary>
/// 服务员信息类
/// </summary>
public class 服务员
{
//服务员个人信息
private string name;//名字
private int age;//年龄
private string sex;//性别
private 工作信息 messages = new 工作信息();
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
public string Sex { get => sex; set => sex = value; }
public void Display()
{
Console.WriteLine("姓名:" + name + " 年龄:" + age + " 性别:" + sex);
Console.WriteLine("工资:" + messages.Salary + " 入职时间:" + messages.EntryTime);
}
public void Set工作信息(int salary, string entryTime)
{
messages.Salary = salary;
messages.EntryTime = entryTime;
}
public object Clone()
{ //浅拷贝
//创建当前 Object 的浅表副本。
return (object)this.MemberwiseClone();
}
public object DeepClone()
{ //深拷贝
服务员 other = (服务员)this.MemberwiseClone();
other.messages = new 工作信息();
return other;
}
}
测试
using System;
class Program
{
static void Main(string[] args)
{
服务员 a1 = new 服务员();
a1.Name = "张三";
a1.Age = 19;
a1.Sex = "男";
a1.Set工作信息(3000, "2021年1月25日");
a1.Display();
//----------------------------------------------------------------
Console.WriteLine("浅拷贝:");
服务员 a2 = (服务员)a1.Clone();
a2.Name = "李武";
a2.Age = 23;
a2.Set工作信息(2500, "2021年4月12日");
a2.Display();
a1.Display();
//----------------------------------------------------------------
Console.WriteLine("深拷贝:");
服务员 a3 = (服务员)a1.DeepClone();
a3.Name = "李四";
a3.Set工作信息(10000,"2014年3月14日");
a3.Display();
a1.Display();
a2.Display();
Console.Read();
}
}
输出示例
设计模式------首页