首页 > 代码库 > 设计模式 - 原型模式

设计模式 - 原型模式

原型模式从字面上来看, 可能还不是那么通俗, 通俗点讲, 可以说是拷贝模式.

 从拷贝来说, 有完全拷贝, 和不完全拷贝. 就仿佛孙猴子的吹毛生猴, 但是这些小猴子明显就没有孙悟空本体厉害, 这种拷贝, 算是浅拷贝吧. 

既然有浅拷贝, 那肯定也是有深拷贝的. 深拷贝就是小猴子与孙悟空本体一样厉害, 无论是从本事还是从长相, 都是一样的

一、原型

/// <summary>
/// 原型
/// </summary>
abstract public class Prototype
{
public int Id { get; set; }

public string Name { get; set; }

public List<int> Size = new List<int>();

public Prototype(int id)
{
    this.Id = id;
}

abstract public Prototype Clone();
}

原型上, 我放了一个值类型, 一个字符串, 一个整形集合, 在原型模式下, 我会修改这几个值, 来观察克隆之后的变化

 

二、浅拷贝

public class Concrete1 : Prototype
{
    public Concrete1(int id)
        : base(id)
    { }

    public override Prototype Clone()
    {
        return (Prototype)this.MemberwiseClone();
    }
}

测试代码:

Console.WriteLine("--------------浅拷贝----------------------");
Concrete1 p1 = new Concrete1(1);
p1.Name = "Name";
p1.Size.AddRange(new int[] { 1, 2, 3, 4, 5 });
Concrete1 c1 = (Concrete1)p1.Clone();
Console.WriteLine("Before Concrete1 change");
Console.WriteLine("Cloned : Id - {0}, Name - {1}, Size - {2}", c1.Id, c1.Name, string.Join(",", c1.Size));

Console.WriteLine();
p1.Id = 2;
p1.Name = "p1.Name";
p1.Size.AddRange(new int[] { 6, 7, 8, 9 });

Console.WriteLine("After Concrete1 changed");
Console.WriteLine("Cloned : Id - {0}, Name - {1}, Size - {2}", c1.Id, c1.Name, string.Join(",", c1.Size));

结果:

技术分享

可以看到, 我在克隆之后, 修改了原型集合的值,  克隆对象也跟着改变了, 说明他们的集合变量指向同一块堆空间. 

Console.WriteLine("p1.Size == c1.Size, {0}", p1.Size == c1.Size);

技术分享

有图有真相.

 

三、深拷贝

public class Concrete2 : Prototype
{
    public Concrete2(int id)
        : base(id)
    { }

    public override Prototype Clone()
    {var jsonStr = JsonConvert.SerializeObject(this);return JsonConvert.DeserializeObject<Concrete2>(jsonStr);
    }
}

测试代码:

Console.WriteLine("--------------深拷贝----------------------");
Concrete2 p2 = new Concrete2(2);
p2.Name = "Name";
p2.Size.AddRange(new int[] { 1, 2, 3, 4, 5 });
Concrete2 c2 = (Concrete2)p2.Clone();
Console.WriteLine("Before Concrete2 change");
Console.WriteLine("Cloned : Id - {0}, Name - {2}, Size - {2}", c2.Id, c2.Name, string.Join(",", c2.Size));

Console.WriteLine();
p2.Id = 2;
p2.Name = "p2.Name";
p2.Size.AddRange(new int[] { 6, 7, 8, 9 });

Console.WriteLine("After Concrete2 changed");
Console.WriteLine("Cloned : Id - {0}, Name - {2}, Size - {2}", c2.Id, c2.Name, string.Join(",", c2.Size));

Console.WriteLine("p2.Size == c2.Size, {0}", p2.Size == c2.Size);

 结果:

技术分享

可以看到, 拷贝实体并没有任何变化, 说明他们已经是两个独立的分开的实体. 并没有共同的变量引用(方法引用除外).

在这里, 我实现深拷贝的方式是通过序列化的方式, 当然还有很多别的方式. 可以自己实现. C#提供的那个克隆方法, 是浅拷贝的实现.

C#有一个接口:ICloneable, 如果不想做成抽象类, 也可以通过这个接口去实现.

 

四、个人应用

就我个人在项目中的应用来看, 我使用过结构克隆.

Datatble这个变量, 无论是b/s, 还是c/s, 应该都是用过的吧.

它有一个Clone方法, 可以用来克隆表结构和约束, 相当方便, 我不需要再去做一遍繁杂的表结构创建.

 

参考:

大话设计模式

C#设计模式(9)

设计模式 - 原型模式