• 设计模式


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

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

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

    一、原型

    /// <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)

  • 相关阅读:
    serial number
    python getopt
    python readline,seek
    linux scp
    jenkinsapi
    windows kill process
    python time
    python configparse
    解决某些.net不方便解决的问题,解决方法就是 DHTML
    (转)windows XP 系统服务“关闭”详细列表,释放N多内存,128也够用了!
  • 原文地址:https://www.cnblogs.com/elvinle/p/6163716.html
Copyright © 2020-2023  润新知