原型模式

概述

有时候需要多次创建某一类型对象,为了简化创建过程,可以只创建一个对象,然后再通过克隆的方法复制出多个相同的对象


深克隆与浅克隆

通常情况下,一个类包含一些成员对象,在使用原型模式克隆对象时,根据其成员对象是否也克隆,原型模式可分为两种形式:深克隆和浅克隆

  • 浅克隆:被复制对象的对象成员变量具有与原来对象相同的值,即引用仍指向原来对象
  • 深克隆:被复制对象的对象成员变量指向被复制过的新对象,而不是原有被引用的对象

Java 提供的 clone() 方法将对象复制一份并返回给调用者,一般而言,clone() 方法满足:

  1. 对任何对象 x,都有 clone() != x,即克隆对象与原对象不是同一个对象
  2. 对任何对象 x,都有 x.clone().getClass() == x.getClass(),即克隆对象与原对象的类型一样
  3. 如果对象的 equals() 方法定义恰当,那么x.clone().equals(x) 应该成立

模式实例(浅克隆)

现需提供一个邮件复制功能,对于已经创建好的邮件对象,可以通过复制的方式创建一个新的邮件对象。本例使用浅克隆实现邮件复制,即复制邮件(E-mail)的同时不复制附件

原型类 Email(邮件类)

public class Email implements Cloneable {

  private Attachment attachment = null;

  public Email() {

  }

  ...
    
  @Override
  public Object clone() {

      Email clone = null;

      try {
          clone = (Email) super.clone();
      } catch (CloneNotSupportedException e) {
          e.printStackTrace();
      }
      return clone;
  }
}

附件类 Attachment

public class Attachment {

    public void download() {
        System.out.println("下载附件");
    }
}

测试类

public class Client {

    public static void main(String[] args) {

        Email email = new Email(new Attachment());

        Email copyEmail = (Email) email.clone();

        System.out.println(email == copyEmail);
        System.out.println(email.getAttachment() == copyEmail.getAttachment());
    }
}

输出结果如下:

在这里插入图片描述

复制得到的对象与原型对象的引用不一致,但两个对象的成员对象是同一个,说明虽然对象本身复制了一份,但其成员对象在内存中没有复制,原型对象与克隆对象都维持了对相同成员对象的引用


模式实例(深克隆)

用深克隆实现邮件复制

Email 作为具体类,由于实现的是深克隆,无须使用 Object 的clone()方法,通过序列化的方法实现深克隆

public class Email implements Serializable {

    private Attachment attachment = null;

    public Email() {

        this.attachment = new Attachment();
    }

    public Attachment getAttachment() {

        return attachment;
    }

    public Object deepclone() throws IOException, ClassNotFoundException {

        //将对象写入流中
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bao);
        oos.writeObject(this);

        //将对象从流中取出
        ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (ois.readObject());
    }
}

附件类 Attachment

public class Attachment implements Serializable {

    public void download() {
        System.out.println("下载附件");
    }
}

测试类

public class Client {

    public static void main(String[] args) {

        Email email, copyEmail = null;

        email = new Email();

        try {
            copyEmail = (Email) email.deepclone();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        System.out.println(email == copyEmail);
        System.out.println(email.getAttachment() == copyEmail.getAttachment());
    }
}

输出结果如下:

在这里插入图片描述

复制得到的对象与原型对象的引用不一致,原型对象与克隆对象对成员对象的引用不相同,说明其成员对象也复制了一份

posted @   低吟不作语  阅读(577)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示