# 原型模式
属于创建型模式。
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
原型模式是通过拷贝一个现有对象生成新的对象,当直接创建对象的代价比较大时,则采用这种模式。
拷贝分为深拷贝和浅拷贝,接下来将分别介绍。
使用场景:
- 资源优化
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等
- 性能和安全要求的场景
- 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
- 一个对象多个修改者的场景
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用
- 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现。通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者
# 深拷贝和浅拷贝
当复制一个对象时,由于其属性复制后产生的效果不同,而产生了深拷贝与浅拷贝。
对于值类型,深拷贝和浅拷贝都是一样的,都是对原始数据的复制,修改原始数据,不会对复制数据产生影响。
对于静态的部分,都不会复制。
两者的区别,在于对引用属性的复制。
# 浅拷贝
创建一个新对象,如果字段是引用类型,则复制引用但不复制引用的对象,因此,原始对象和其副本都引用同一个对象
# 深拷贝
创建一个新对象,如果字段是引用类型,则复制引用和引用的对象,因此,原始对象和其副本是不同的两个对象
# 浅拷贝实现
# 类图
# 代码
# 需要拷贝的类
namespace CreationalPatterns_PrototypePattern.ShallowCopy | |
{ | |
/// <summary> | |
/// 效果 | |
/// </summary> | |
public class Effect | |
{ | |
public string EffectName; | |
public Effect(string effectName) | |
{ | |
EffectName = effectName; | |
} | |
} | |
} |
namespace CreationalPatterns_PrototypePattern.ShallowCopy | |
{ | |
/// <summary> | |
/// 形状 | |
/// </summary> | |
public class Shape | |
{ | |
public string ShapName; | |
public Effect MainEffect; | |
public Shape(string shapName, string effectName) | |
{ | |
ShapName = shapName; | |
MainEffect = new Effect(effectName); | |
} | |
/// <summary> | |
/// 形状和效果 | |
/// </summary> | |
public void MyShap() | |
{ | |
Console.WriteLine("ShapName: " + ShapName + "\nEffectName: " + MainEffect.EffectName); | |
} | |
/// <summary> | |
/// 生成克隆(浅拷贝) | |
/// </summary> | |
public Shape GetClone() | |
{ | |
return (Shape)MemberwiseClone(); | |
} | |
} | |
} |
# 测试
namespace CreationalPatterns_PrototypePattern.ShallowCopy | |
{ | |
public class Program | |
{ | |
private static void Main() | |
{ | |
Shape shape_0 = new Shape("shape_0", "Transparent"); | |
Shape shape_1 = shape_0.GetClone(); | |
// 注意,这里将引用指向了新的 string 类型的对象 | |
shape_1.ShapName = "shape_1"; | |
shape_1.MainEffect.EffectName = "Opaque"; | |
shape_0.MyShap(); | |
Console.WriteLine(); | |
shape_1.MyShap(); | |
} | |
} | |
} |
运行结果:
ShapName: shape_0
EffectName: Opaque
ShapName: shape_1
EffectName: Opaque
# 深拷贝实现
- 使用对象复制方法:如果类中包含引用类型的成员变量,可以通过递归调用成员变量的复制方法来实现深拷贝。
- 使用序列化和反序列化:这是一种常见的实现深拷贝的方式。可以通过将对象进行序列化为字节流,然后再反序列化生成一个全新的对象。
# 使用对象复制方法
- 相较于浅拷贝,只需要更改 Shape 类
- 使用不同的命名空间做出区分
using CreationalPatterns_PrototypePattern.ShallowCopy; | |
namespace CreationalPatterns_PrototypePattern.DeepCopy_ObjectCopy | |
{ | |
/// <summary> | |
/// 形状 | |
/// </summary> | |
public class Shape | |
{ | |
public string ShapName; | |
public Effect MainEffect; | |
public Shape(string shapName, string effectName) | |
{ | |
ShapName = shapName; | |
MainEffect = new Effect(effectName); | |
} | |
/// <summary> | |
/// 形状和效果 | |
/// </summary> | |
public void MyShap() | |
{ | |
Console.WriteLine("ShapName: " + ShapName + "\nEffectName: " + MainEffect.EffectName); | |
} | |
/// <summary> | |
/// 生成克隆(深拷贝) | |
/// </summary> | |
public Shape GetClone() | |
{ | |
Shape temp = (Shape)MemberwiseClone(); | |
temp.MainEffect = new Effect(this.MainEffect.EffectName); | |
return temp; | |
} | |
} | |
} |
用于测试的代码与浅拷贝相同,但运行结果不同:
ShapName: shape_0
EffectName: Transparent
ShapName: shape_1
EffectName: Opaque
# 使用序列化和反序列化
# 类图
# 代码
# 处理序列化和反序列化
- 要进行深拷贝的类及其成员必须是可序列化的,所以需要将它们标记为 [Serializable]
using System.Runtime.Serialization.Formatters.Binary; | |
namespace CreationalPatterns_PrototypePattern.DeepCopy_Serialization | |
{ | |
public class DeepCopyHelper | |
{ | |
public static T DeepCopy<T>(T obj) | |
{ | |
if (obj == null) | |
{ | |
return default(T); | |
} | |
BinaryFormatter formatter = new BinaryFormatter(); | |
MemoryStream stream = new MemoryStream(); | |
using (stream) | |
{ | |
formatter.Serialize(stream, obj); | |
stream.Seek(0, SeekOrigin.Begin); | |
return (T)formatter.Deserialize(stream); | |
} | |
} | |
} | |
} |
# 用于拷贝的类
namespace CreationalPatterns_PrototypePattern.DeepCopy_Serialization | |
{ | |
[Serializable] | |
/// <summary> | |
/// 效果 | |
/// </summary> | |
public class Effect | |
{ | |
public string EffectName; | |
public Effect(string effectName) | |
{ | |
EffectName = effectName; | |
} | |
} | |
} |
namespace CreationalPatterns_PrototypePattern.DeepCopy_Serialization | |
{ | |
[Serializable] | |
/// <summary> | |
/// 形状 | |
/// </summary> | |
public class Shape | |
{ | |
public string ShapName; | |
public Effect MainEffect; | |
public Shape(string shapName, string effectName) | |
{ | |
ShapName = shapName; | |
MainEffect = new Effect(effectName); | |
} | |
/// <summary> | |
/// 形状和效果 | |
/// </summary> | |
public void MyShap() | |
{ | |
Console.WriteLine("ShapName: " + ShapName + "\nEffectName: " + MainEffect.EffectName); | |
} | |
/// <summary> | |
/// 生成克隆(深拷贝) | |
/// </summary> | |
public Shape GetClone() | |
{ | |
return DeepCopyHelper.DeepCopy<Shape>(this); | |
} | |
} | |
} |
# 测试
namespace CreationalPatterns_PrototypePattern.DeepCopy_Serialization | |
{ | |
public class Program | |
{ | |
private static void Main() | |
{ | |
Shape shape_0 = new Shape("shape_0", "Transparent"); | |
Shape shape_1 = shape_0.GetClone(); | |
// 注意,这里将引用指向了新的 string 类型的对象 | |
shape_1.ShapName = "shape_1"; | |
shape_1.MainEffect.EffectName = "Opaque"; | |
shape_0.MyShap(); | |
Console.WriteLine(); | |
shape_1.MyShap(); | |
} | |
} | |
} |
运行结果:
ShapName: shape_0
EffectName: Transparent
ShapName: shape_1
EffectName: Opaque