经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
设计模式-创建型-原型模式
来源:cnblogs  作者:酷学大叔  时间:2019/9/17 10:36:20  对本文有异议

引言:

  原型模式是什么?它是在什么场景下被提出的呢?本章节,我们将详细了解下原型模式。

  在软件系统中,当创建一个类的实例过程过于昂贵或复杂,并且我们需要创建多个这样类的实例时,如果我们通过new来创建类实例,这就会增加创建类的复杂度和创建过程与客户代码复杂的耦合度。如果采用工厂模式来创建这样的实例对象的话,随着产品类的不断增加,导致子类的数量不断增多,也导致了相应工厂类的增加,维护的代码维度增加了,因为有产品和工厂两个维度了,反而增加了系统复杂程度,所以在这里使用工厂模式来封装类创建过程并不合适。由于每个类实例都是相同的(类型相同),但是每个实例的状态参数会有不同,如果状态数值也相同就没意义了,有一个这样的对象就可以了。当我们需要多个相同的类实例时,可以通过对原来对象拷贝一份来完成创建,这个思路正是原型模式的实现方式。

定义:

  原型模式就是通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个对象的方法来创建更多的同类型对象。 

原型模式的两种类型: 

  object类的clone方法只会拷贝对象中基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。 

  1. 1 internal class Program
  2. 2 {
  3. 3 private static void Main(string[] args)
  4. 4 {
  5. 5 SunWukong sunwukong = new SunWukong()
  6. 6 {
  7. 7 Id = 1,
  8. 8 Name = "孙悟空",
  9. 9 Weapon = new Weapon()
  10. 10 {
  11. 11 Name = "如意金箍棒"
  12. 12 }
  13. 13 };
  14. 14 SunWukong xingzhesun = (SunWukong)sunwukong.Clone();
  15. 15 Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
  16. 16 Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
  17. 17 Console.WriteLine("===============================");
  18. 18
  19. 19 // 验证克隆后属性之间是否共享
  20. 20 xingzhesun.Id = 2;
  21. 21 xingzhesun.Name = "行者孙";
  22. 22 xingzhesun.Weapon.Name = "钉耙";
  23. 23 Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
  24. 24 Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
  25. 25 // 从结果可以看出,对于基本类型属性,克隆之后不共享,而对于对象来说是共享的,这就是浅拷贝
  26. 26 Console.WriteLine("===============================");
  27. 27 Console.WriteLine($"孙悟空的武器{sunwukong.Weapon.GetHashCode()},行者孙的武器{sunwukong.Weapon.GetHashCode()}");
  28. 28 // 打印hashcode值可以看出,克隆后的实例与原型的Weapon指向同一个地址
  29. 29 }
  30. 30 }
  31. 31
  32. 32 internal class SunWukong : ICloneable
  33. 33 {
  34. 34 public int Id { get; set; }
  35. 35 public string Name { get; set; }
  36. 36 public Weapon Weapon { get; set; }
  37. 37
  38. 38 public object Clone()
  39. 39 {
  40. 40 return this.MemberwiseClone();
  41. 41 }
  42. 42 }
  43. 43
  44. 44 internal class Weapon
  45. 45 {
  46. 46 public string Name { get; set; }
  47. 47 }
view code

 

  .net中提供了原型,即System命名空间下的接口ICloneable,只要实现该接口的Clone方法就可以之间原型拷贝。上述代码中遗留了一个问题,如何实现深拷贝问题。 

  1. 1 internal class Program
  2. 2 {
  3. 3 private static void Main(string[] args)
  4. 4 {
  5. 5 SunWukong sunwukong = new SunWukong()
  6. 6 {
  7. 7 Id = 1,
  8. 8 Name = "孙悟空",
  9. 9 Weapon = new Weapon()
  10. 10 {
  11. 11 Name = "如意金箍棒"
  12. 12 }
  13. 13 };
  14. 14 SunWukong xingzhesun = (SunWukong)sunwukong.Clone();
  15. 15 // 引用类型再进行拷贝
  16. 16 xingzhesun.Weapon = (Weapon)xingzhesun.Weapon.Clone();
  17. 17 Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
  18. 18 Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
  19. 19 Console.WriteLine("===============================");
  20. 20 xingzhesun.Id = 2;
  21. 21 xingzhesun.Name = "行者孙";
  22. 22 xingzhesun.Weapon.Name = "钉耙";
  23. 23 Console.WriteLine($"{xingzhesun.Id}-{xingzhesun.Name}-{xingzhesun.Weapon.Name}");
  24. 24 Console.WriteLine($"{sunwukong.Id}-{sunwukong.Name}-{sunwukong.Weapon.Name}");
  25. 25 Console.WriteLine("===============================");
  26. 26 Console.WriteLine($"孙悟空的武器{sunwukong.Weapon.GetHashCode()},行者孙的武器{xingzhesun.Weapon.GetHashCode()}");
  27. 27 }
  28. 28 }
  29. 29
  30. 30 internal class SunWukong : ICloneable
  31. 31 {
  32. 32 public int Id { get; set; }
  33. 33 public string Name { get; set; }
  34. 34 public Weapon Weapon { get; set; }
  35. 35
  36. 36 public object Clone()
  37. 37 {
  38. 38 return this.MemberwiseClone();
  39. 39 }
  40. 40 }
  41. 41
  42. 42 internal class Weapon : ICloneable
  43. 43 {
  44. 44 public string Name { get; set; }
  45. 45
  46. 46 public object Clone()
  47. 47 {
  48. 48 return this.MemberwiseClone();
  49. 49 }
  50. 50 }
view code 

 

深拷贝:

  1、复制对象的基本数据类型的成员变量值。

  2、为所有引用类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝。

  3、深拷贝实现方式1:重写clone方法。

  4、深拷贝实现方式2:通过对象序列化。 

  1. 1 //对象深拷贝
  2. 2 public static T Copy<T>(T oldObject) where T : class,new()
  3. 3 {
  4. 4 T newOrder = new T();
  5. 5 MemoryStream stream = new MemoryStream();
  6. 6 BinaryFormatter bf = new BinaryFormatter();
  7. 7 bf.Serialize(stream, oldObject);
  8. 8 stream.Position = 0;
  9. 9 newOrder = (bf.Deserialize(stream) as T);
  10. 10 return newOrder;
  11. 11 }
view code

原型模式的注意事项和细节:

  1、创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率。

  2、不用重新初始化对象,而是动态地获取对象运行时的状态。

  3、如果原始对象发生变化(增加或减少属性),其它克隆对象也会发生相应的变化,无需修改代码。

  4、在实现深克隆的时候可能需要比较复杂的代码。    

  5、使用原型模式复制不会调用类的构造方法。因为对象的复制是通过调用clone方法完成的,它直接在内存种复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。单例模式中,我们通过私有化构造函数来实现单例模式,但clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的。

原型模式的优点:

  1、原型模式向客户隐藏了创建新实例的复杂性。

  2、原型模式允许动态增加或较少产品类。

  3、原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。

  4、产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构。

缺点:

  1、需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改源码,即违反了OCP原则

参考:https://www.cnblogs.com/zhili/p/PrototypePattern.html

   https://yq.aliyun.com/articles/485574 

原文链接:http://www.cnblogs.com/az4215/p/11525391.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号