经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
看完这篇原型设计模式,还不会,请你吃瓜
来源:cnblogs  作者:realyrare  时间:2023/2/20 15:19:20  对本文有异议

概述

使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

在软件系统开发中,有时候会遇到这样的情况:我们需要用到多个相同实例,最简单直接的方法是通过多次调用new方法来创建相同的实例。

  1. student s=new student();
  2. student s1=new student();
  3. student s2=new student();

但是有一个问题,如果我用要使用的实例创建起来十分耗费资源,或者创建起来步骤比较繁琐,上边的代码缺点就暴露出来了:耗费资源,每次创建实例都要重复繁琐的创建过程。原始模式可以很好地解决这个问题,使用原型模式我们不需要每次都new一个新的实例,而是通过拷贝原有的对象来完成创建,这样我们就不需要在内存中创建多个对象,也不需要重复复杂的创建过程了。下边以克隆学生为例解释原型模式的用法,代码非常简单。

C#通过this.MemberwiseClone()实现原型模式

  1. /// <summary>
  2. /// //原型抽象类
  3. /// </summary>
  4. public abstract class StudentPrototype
  5. {
  6. public string Name { get; }
  7. public StudentPrototype(string name)
  8. {
  9. Name=name;
  10. }
  11. public abstract StudentPrototype Clone();
  12. }
  13. /// <summary>
  14. /// 学生类继承原型抽象类 并重写Clone();
  15. /// </summary>
  16. public class Student : StudentPrototype
  17. {
  18. public Student(string name) : base(name)
  19. {
  20. }
  21. public override StudentPrototype Clone()
  22. {
  23. //浅拷贝
  24. //值类型成员:全都复制一份,并且搞一份新的。
  25. //引用类型:只是复制其引用,并不复制其对象。
  26. return (StudentPrototype)this.MemberwiseClone();
  27. }
  28. }
  1. Console.WriteLine("原型设计模式");
  2. Student student=new Student("mhg");
  3. Student student1=(Student)student.Clone();
  4. Console.WriteLine(student.GetHashCode());
  5. Console.WriteLine(student1.GetHashCode());
  6. Console.WriteLine(student1.Name);

结论:实现该原型模式,第一需要定义一个抽象类,定义一个抽象方法;第二写一个类继承该抽象类。重写抽象方法即可。重写抽象方法的逻辑使用this.MemberwiseClone();

C#自己继承ICloneable实现原型模式

  1. public class Teacher:ICloneable
  2. {
  3. public Teacher(string name)
  4. {
  5. Name=name;
  6. }
  7. public string Name { get; }
  8. public object Clone()
  9. {
  10. return this.MemberwiseClone();
  11. }
  12. }
  1. Console.WriteLine("C#自己继承ICloneable");
  2. Teacher teacher=new Teacher("mhg2");
  3. Teacher teacher2=(Teacher)teacher.Clone();

  Console.WriteLine(teacher.GetHashCode());
  Console.WriteLine(teacher2.GetHashCode());
  Console.WriteLine(teacher2.Name);

结论:定义一个类继承ICloneable,然后使用this.MemberwiseClone()实现,这种方式更简单。

这里需要注意一点:通过this.MemberWiseClone()获取一个对象的实例属于浅拷贝,对实例的简单类型属性进行全值拷贝(包含string类型),对复杂类型属性只拷贝了引用。

下面咱们验证一下浅拷贝确实只对值类型成员全部复制了一份,搞成了一份新的,对于引用类型,只是复制了其引用,并不复制其对象。

我们还是继续用Teacher这个类,在这个类里面增加一个引用类型MyStudent,咱上代码。

  1. public class Teacher : ICloneable
  2. {
  3. public string? Name { get; set; }
  4. public MyStudent? MyStudent { get; set; }
  5. public object Clone()
  6. {
  7. return this.MemberwiseClone();
  8. }
  9. public void Show()
  10. {
  11. Console.WriteLine($"Teacher:{Name}");
  12. Console.WriteLine($"MyStudent name:{MyStudent.Name}");
  13. Console.WriteLine($"MyStudent Age:{MyStudent.Age}");
  14. }
  15. }
  16. public class MyStudent
  17. {
  18. public string Name { get; set; }
  19. public string Age { get; set; }
  20. }

看下执行结果

通过执行克隆了一份新对象,修改了Teacher.Mystudent.Name和Teacher.Mystudent.Age的值,其teacher对象Mystudent.Name和MyStudent.Age值也会发生变化,而修改了Teacher2.Name的值,其teacher对象的name却没有发生变化。也就验证我们上面所说的,原型浅拷贝关于值类型全部复制一份,对于引用只复制其引用,这点特别重要,很多人搞不明白,多动手实践一下。

那如果就上面的问题而言,我们现在既想对原型里面的值类型复制一份新的,也想把引用类型复制一份新的对象,并不仅仅只是再复制其引用,该怎么实现呢?

通过原型伪深拷贝实现

  1. public class Teacher : ICloneable
  2. {
  3. public string? Name { get; set; }
  4. public MyStudent? MyStudent { get; set; }
  5. public Teacher()
  6. {
  7. MyStudent=new MyStudent();
  8. }
  9. private Teacher(MyStudent myStudent)
  10. {
  11. MyStudent=(MyStudent)myStudent.Clone();
  12. }
  13. public object Clone()
  14. {
  15. //在创建新对象的时候把工作经验这个引用类型也复制一份
  16. Teacher teacher1 = new Teacher(MyStudent)
  17. {
  18. Name = Name
  19. };
  20. return teacher1;
  21. //如果依然调用this.MemberwiseClone();引用类型,就永远不可能被复制一份新的
  22. //return this.MemberwiseClone(); //这种写法只能拷贝值类型
  23. }
  24. public void Show(string objectName)
  25. {
  26. Console.WriteLine($"-------------{objectName}-start----------------");
  27. Console.WriteLine($"{objectName}:{Name}");
  28. Console.WriteLine($"MyStudent-name:{MyStudent.Name}");
  29. Console.WriteLine($"MyStudent-Age:{MyStudent.Age}");
  30. Console.WriteLine($"-------------{objectName}-end----------------\r\n");
  31. }
  32. }
  33. public class MyStudent:ICloneable
  34. {
  35. public string Name { get; set; }
  36. public string Age { get; set; }
  37. public object Clone()
  38. {
  39. return this.MemberwiseClone();
  40. }
  41. }

来看看执行结果

通过上述代码运行可以看出,teacher1、teacher2、teacher3几个对象的创建...最后不仅把值类型全部复制了一份新的,引用类型也复制了一份对象,不再是复制其引用了。

目前这种原型创建还只是伪深拷贝,如果在MyStudent类中在出现一个引用类型,那么就需要使用递归。这种方式显而易见是有问题的,如果要真正的实现深拷贝,需要通过反射和序列化来实现.

总结

上述案例我们分别讲了原型浅拷贝,原型伪深拷贝,如何实现真正的深拷贝,其实也很简单,这次就不再往下写了,文章写短了没人看,写长了更没人看!关于案例中的其他问题,有疑问,欢迎交流!

 

原文链接:https://www.cnblogs.com/mhg215/p/17127080.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号