zoukankan      html  css  js  c++  java
  • 原型模式(浅克隆和深克隆)

    原型模式是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的.
    原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据.

    原型模式中的拷贝分为"浅拷贝"和"深拷贝":
    浅克隆: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象.
    深克隆: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制.

    首先来看一些原型模式的实现代码,这里先运用浅克隆来实现 ,首先建立一个类来表示班级

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Threading;
     4 using System.Threading.Tasks;
     5 
     6 namespace 设计模式之原型模式
     7 {
     8     /// <summary>
     9     /// 班级类
    10     /// </summary>
    11     public class Class
    12     {
    13         public int Num { get; set; }
    14         public string Remark { get; set; }
    15     }
    16 
    17     /// <summary>
    18     /// 学生类
    19     /// </summary>
    20     class StudentPrototype
    21     {
    22         //模拟复杂的构造函数
    23         private StudentPrototype()
    24         {
    25             Thread.Sleep(2000);
    26             long lResult = 0;
    27             for (int i = 0; i < 1000000000; i++)
    28             {
    29                 lResult += i;
    30             }
    31             Console.WriteLine("{0}被构造..", this.GetType().Name);
    32         }
    33 
    34         private static StudentPrototype _StudentPrototype = null;
    35 
    36         static StudentPrototype()
    37         {
    38             _StudentPrototype = new StudentPrototype()
    39             {
    40                 Id = 337,
    41                 Name = "学友",
    42                 Class=new Class()
    43                 {
    44                     Num=1,
    45                     Remark="BIGDong"
    46                 }
    47             };
    48         }
    49         /// <summary>
    50         /// 克隆出实体类
    51         /// </summary>
    52         /// <returns></returns>
    53         public static StudentPrototype CreatInstance()
    54         {
    55             //克隆一个对象(浅克隆)
    56             StudentPrototype studentPrototype = (StudentPrototype)_StudentPrototype.MemberwiseClone();
    57           
    58             return studentPrototype;
    59         }
    60 
    61         public int Id { get; set; }
    62         public string Name { get; set; }
    63         public Class Class{ get; set; }
    64 
    65         public void Study()
    66         {
    67             Console.WriteLine("{0}在学习设计模式",this.Name);
    68         }
    69     }
    70 }

    实例类可以调用MemberwiseClone函数来为该实体类克隆出一个副本,那么我们来做下测试

     1 namespace 设计模式之原型模式
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             StudentPrototype stundet1 = StudentPrototype.CreatInstance();
     8             StudentPrototype stundet2 = StudentPrototype.CreatInstance();
     9             stundet1.Name = "华仔";
    10             stundet1.Id = 2;
    11             stundet1.Class.Num = 3;
    12             stundet1.Class.Remark = "郭富城";
    13 
    14             Console.WriteLine(string.Format("stundet1.Name是{0},stundet1.Id是{1},stundet1.Class.Num是{2},stundet1.Class.Remark是{3},"
    15             , stundet1.Name, stundet1.Id, stundet1.Class.Num, stundet1.Class.Remark));
    16 
    17             Console.WriteLine(string.Format("stundet2.Name是{0},stundet2.Id是{1},stundet2.Class.Num是{2},stundet2.Class.Remark是{3},"
    18         , stundet2.Name, stundet2.Id, stundet2.Class.Num, stundet2.Class.Remark));
    19 
    20             Console.ReadKey();
    21         }
    22     }
    23 }

     

    从调试可以看出这两个被使用浅克隆生成的对象,当第一个被对象修改值的时候,第二个对象里面的值对象并没有被覆盖掉,而第二个对象里的class引用类全被改变了

    说到这里就要解释下,引用类型指向都是一个内存地址,而这个内存地址指向的是推里的一个值,上面的例子创建了两个对象都是指向同一块内存地址,所以只要改变一个的值

    另外一个也会跟着改变(这和单例模式很像),然后这里还有一点说明,在StudentPrototype类里的string字段也是引用类型,为什么它没被覆盖掉呢?

    在解释这个问题之前,我们上一段代码来解决上面的class不会被覆盖的,然后再解释string为什么不会被覆盖的问题

    把上面赋值的地方之间生成一个新的对象,这样就将内存地址指向一个新的值

    我们可以看到 现在class不会被覆盖掉了,其实string每次在赋值的时候也是这样子,重新生成一个内存地址,指向一个新的值,所以也不会被覆盖

    而这种方式也正是我们讲的深克隆

    我们也可以在类的构造函数里直接添加深克隆的代码,但是这样每一个新的类就得创建在构造函数写一大堆,是麻烦的,其实我们可以使用序列化的方式

    来实习这一繁琐的步骤,首先要在类前加上序列化的特性

    然后写一个创建序列化和反序列化类,通过反序列出来的对象都是重新生成的

     1 namespace 设计模式之原型模式
     2 {
     3     class SerializeHelper
     4     {
     5         /// <summary>
     6         /// 将一个对象转成字符串(序列化)
     7         /// </summary>
     8         /// <param name="targat">对象</param>
     9         /// <returns></returns>
    10         public static string Serializble(object targat)
    11         {
    12             using (MemoryStream stream = new MemoryStream())
    13             {
    14                 new BinaryFormatter().Serialize(stream, targat);
    15                 return Convert.ToBase64String(stream.ToArray());
    16             }
    17         }
    18 
    19         /// <summary>
    20         /// 将字符串转成对象(反序列化)
    21         /// </summary>
    22         /// <typeparam name="T"></typeparam>
    23         /// <param name="target">字符串</param>
    24         /// <returns></returns>
    25         public static T Derializable<T>(string target)
    26         {
    27             byte[] targetArray = Convert.FromBase64String(target);
    28             using (MemoryStream stream = new MemoryStream(targetArray))
    29             {
    30                 return (T)(new BinaryFormatter().Deserialize(stream));
    31             }
    32         }
    33 
    34         /// <summary>
    35         /// 外界调用接口
    36         /// </summary>
    37         /// <typeparam name="T">泛型</typeparam>
    38         /// <param name="t"></param>
    39         /// <returns></returns>
    40         public static T DeepClone<T>(T t)
    41         {
    42             return Derializable<T>(Serializble(t));
    43         }
    44 
    45     }
    46 }

    然后获得实例类的GetInstance函数里调用

    这样输出的结果也就是深克隆要的效果了

  • 相关阅读:
    地图校正方法心得
    投影的心得点滴
    android 打包 apk keystore
    scp命令详解
    ubuntu11.10真机调试nopermissions
    android adb server is out of date
    ubuntu删除默认jdk
    android 运行 错误 总结
    android file .apk is not a valid zip file adb install
    ubuntu系统目录结构
  • 原文地址:https://www.cnblogs.com/BigDong/p/8045104.html
Copyright © 2011-2022 走看看