- 携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
前言
原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。说完概念大家可能还不是很理解,究竟什么时候使用原型模式呢?或者说什么场景适用原型模式?下文将为大家详解!
问题
在传统开发中,比如我们有一个对象,但我们需要再创建个对象并且与其一样的时候会怎么做,无非就是多new几下嘛,没什么大不了。
static void Main(string[] args)
{
Car car1 = new Car(); // car1对象
car1.SetCarInfo("A车","1.5T");
Car car2 = new Car(); // car2对象
car2.SetCarInfo("A车","1.5T");
// 也可以简单粗暴
car2 = car1;
}
// 车的对象
public class Car
{
public string CarName; // 车名称
public string CarEmissions; // 车排量
// 赋值方法
public void SetCarInfo(string carName,string carEmissions)
{
CarName = carName;
CarEmissions = carEmissions;
}
}
缺点:这样做会导致内存中多分配一个一样的类实例对象,增加复杂度和消耗更多的内存空间,我们应该避免这样的情况出现。
其实原型模式很好的解决了这个问题,通俗来说原型模式就是克隆,从一个对象复制到另外一个对象,并且我们不需要知道细节
原型模式结构
- 原型(Prototype):接口将对克隆方法进行声明。
- 具体原型:实现克隆方法,将对象复制到克隆体。
该类图摘自深入设计模式一书
原型模式实践
浅拷贝
- 了解了各种概念来看代码也是非常易理解,我们先新建原型接口,然后使用原型类实现克隆接口
// 原型
public interface IPrototype
{
Prototype Clone();
}
// 具体原型
public class Prototype : IPrototype
{
public string CarName;
public string CarEmissions;
public Prototype Clone()
{
return (Prototype)this.MemberwiseClone();
}
}
//客户端调用
static void Main(string[] args)
{
Prototype prototype1 = new Prototype();
prototype1.SetCarInfo("A级别车", "1.5L");
Prototype prototype2 = prototype1.Clone();
Console.WriteLine($"Clone后CarName:{prototype2.CarName} CarEmissions:{prototype2.CarEmissions}");
Console.ReadLine();
}
注意:我们在实现clone方法使用了
MemberwiseClone()方法,他究竟有何魔力呢?我们可以看看解释:MemberwiseClone 通过创建新对象,然后将当前对象的非静态字段复制到新对象来创建浅表副本。 如果字段是值类型,则执行字段的逐位副本。 如果字段是引用类型,则会复制引用,但引用对象不是;因此,原始对象及其克隆引用同一对象,该方式也被称之为浅拷贝。
浅拷贝会带来什么问题呢?我们在上述代码进行一些调整,来体现一下问题!新增CarConfig类,在Prototype增加SetCarConfig方法给对象赋值。
浅拷贝:针对引用类型只复制引用不复制引用对象,即原始对象和副本引用同一个对象
深拷贝
深拷贝即是在克隆过程中我们希望三个对象都是不同的,即将引用对象的变量指向新的对象,而不是原有的对象。
-
实现深拷贝方式
- 调用要复制的对象的类构造函数,以创建具有从第一个对象获取的属性值的第二个对象。 这假定对象的值完全由其类构造函数定义。
- MemberwiseClone调用该方法以创建对象的浅表副本,然后将其值与原始对象相同的新对象分配给其值为引用类型的任何属性或字段。
- 将对象序列化为深拷贝,然后将序列化的数据还原到其他对象变量。
- 将反射与递归一起使用来执行深层复制操作。
-
使用序列化实现深拷贝,修改Clone方法!
public Prototype Clone()
{
string target = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<Prototype>(target);
}
- 执行结果
总结
创建的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,使用原型模式可以减少初始化对象的频繁操作,提升了程序的性能!但是要实现原型模式,需要实现Clone方法,也就意味着每个类需要配备一个Clone方法,而且在实现深克隆会导致代码过程较为复杂,序列化的方式还好,使用其他方式相对来说比较复杂。在使用的时候也要考虑场景,将设计模式用到恰到好处,也是一门大学问。