经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
设计模式(六)----创建型模式之原型模式
来源:cnblogs  作者:|旧市拾荒|  时间:2023/2/8 8:57:31  对本文有异议

1、概述

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

2、结构

原型模式包含如下角色:

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。

  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。

  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

接口类图如下:

3、实现

原型模式的克隆分为浅克隆和深克隆。

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址,其对象地址发生了改变。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址,其对象地址也发生了改变。

Java中的Object类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。代码如下:

Realizetype(具体的原型类):

  1. public class Realizetype implements Cloneable {
  2. ?
  3.    public Realizetype() {
  4.        System.out.println("具体的原型对象创建完成!");
  5.   }
  6. ?
  7.    @Override
  8.    protected Realizetype clone() throws CloneNotSupportedException {
  9.        System.out.println("具体原型复制成功!");
  10.        return (Realizetype) super.clone();
  11.   }
  12. }

PrototypeTest(测试访问类):

  1. public class PrototypeTest {
  2.    public static void main(String[] args) throws CloneNotSupportedException {
  3.        Realizetype r1 = new Realizetype();
  4.        Realizetype r2 = r1.clone();
  5. ?
  6.        System.out.println("对象r1和r2是同一个对象?" + (r1 == r2));
  7.   }
  8. }

测试结果

4、案例

用原型模式生成“三好学生”奖状

同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,可以使用原型模式复制多个“三好学生”奖状出来,然后在修改奖状上的名字即可。

类图如下:

代码如下:

  1. //奖状类
  2. public class Citation implements Cloneable {
  3.    private String name;
  4. ?
  5.    public void setName(String name) {
  6.        this.name = name;
  7.   }
  8. ?
  9.    public String getName() {
  10.        return (this.name);
  11.   }
  12. ?
  13.    public void show() {
  14.        System.out.println(name + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
  15.   }
  16. ?
  17.    @Override
  18.    public Citation clone() throws CloneNotSupportedException {
  19.        return (Citation) super.clone();
  20.   }
  21. }
  22. ?
  23. //测试访问类
  24. public class CitationTest {
  25.    public static void main(String[] args) throws CloneNotSupportedException {
  26.        Citation c1 = new Citation();
  27.        c1.setName("张三");
  28. ?
  29.        //复制奖状
  30.        Citation c2 = c1.clone();
  31.        //将奖状的名字修改李四
  32.        c2.setName("李四");
  33. ?
  34.        c1.show();
  35.        c2.show();
  36.   }
  37. }

测试结果

5、使用场景

  • 对象的创建非常复杂,可以使用原型模式快捷的创建对象。

  • 性能和安全要求比较高。

6、扩展(深克隆)

将上面的“三好学生”奖状的案例中Citation类的name属性修改为Student类型的属性。代码如下:

  1. //奖状类
  2. public class Citation implements Cloneable {
  3.    private Student stu;
  4. ?
  5.    public Student getStu() {
  6.        return stu;
  7.   }
  8. ?
  9.    public void setStu(Student stu) {
  10.        this.stu = stu;
  11.   }
  12. ?
  13.    void show() {
  14.        System.out.println(stu.getName() + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
  15.   }
  16. ?
  17.    @Override
  18.    public Citation clone() throws CloneNotSupportedException {
  19.        return (Citation) super.clone();
  20.   }
  21. }
  22. ?
  23. //学生类
  24. public class Student {
  25.    private String name;
  26.    private String address;
  27. ?
  28.    public Student(String name, String address) {
  29.        this.name = name;
  30.        this.address = address;
  31.   }
  32. ?
  33.    public Student() {
  34.   }
  35. ?
  36.    public String getName() {
  37.        return name;
  38.   }
  39. ?
  40.    public void setName(String name) {
  41.        this.name = name;
  42.   }
  43. ?
  44.    public String getAddress() {
  45.        return address;
  46.   }
  47. ?
  48.    public void setAddress(String address) {
  49.        this.address = address;
  50.   }
  51. }
  52. ?
  53. //测试类
  54. public class CitationTest {
  55.    public static void main(String[] args) throws CloneNotSupportedException {
  56. ?
  57.        Citation c1 = new Citation();
  58.        Student stu = new Student("张三", "西安");
  59.        c1.setStu(stu);
  60. ?
  61.        //复制奖状
  62.        Citation c2 = c1.clone();
  63.        //获取c2奖状所属学生对象
  64.        Student stu1 = c2.getStu();
  65.        stu1.setName("李四");
  66. ?
  67.        //判断stu对象和stu1对象是否是同一个对象
  68.        System.out.println("stu和stu1是同一个对象?" + (stu == stu1));
  69. ?
  70.        c1.show();
  71.        c2.show();
  72.   }
  73. }

运行结果为:

说明:

stu对象和stu1对象是同一个对象,就会产生将stu1对象中name属性值改为“李四”,两个Citation(奖状)对象中显示的都是李四。这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。这种情况需要使用深克隆,而进行深克隆需要使用对象流。代码如下:

  1. public class CitationTest1 {
  2.    public static void main(String[] args) throws Exception {
  3.        Citation c1 = new Citation();
  4.        Student stu = new Student("张三", "西安");
  5.        c1.setStu(stu);
  6. ?
  7.        //创建对象输出流对象
  8.        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\b.txt"));
  9.        //将c1对象写出到文件中
  10.        oos.writeObject(c1);
  11.        oos.close();
  12. ?
  13.        //创建对象出入流对象
  14.        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\b.txt"));
  15.        //读取对象
  16.        Citation c2 = (Citation) ois.readObject();
  17.        //获取c2奖状所属学生对象
  18.        Student stu1 = c2.getStu();
  19.        stu1.setName("李四");
  20. ?
  21.        //判断stu对象和stu1对象是否是同一个对象
  22.        System.out.println("stu和stu1是同一个对象?" + (stu == stu1));
  23. ?
  24.        c1.show();
  25.        c2.show();
  26.   }
  27. }

运行结果为:

注意:Citation类和Student类必须实现Serializable接口,否则会抛NotSerializableException异常。

 

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