原型模式
概述
有时候需要多次创建某一类型对象,为了简化创建过程,可以只创建一个对象,然后再通过克隆的方法复制出多个相同的对象
深克隆与浅克隆
通常情况下,一个类包含一些成员对象,在使用原型模式克隆对象时,根据其成员对象是否也克隆,原型模式可分为两种形式:深克隆和浅克隆
- 浅克隆:被复制对象的对象成员变量具有与原来对象相同的值,即引用仍指向原来对象
- 深克隆:被复制对象的对象成员变量指向被复制过的新对象,而不是原有被引用的对象
Java 提供的 clone() 方法将对象复制一份并返回给调用者,一般而言,clone() 方法满足:
- 对任何对象 x,都有 clone() != x,即克隆对象与原对象不是同一个对象
- 对任何对象 x,都有 x.clone().getClass() == x.getClass(),即克隆对象与原对象的类型一样
- 如果对象的 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());
}
}
输出结果如下:
复制得到的对象与原型对象的引用不一致,原型对象与克隆对象对成员对象的引用不相同,说明其成员对象也复制了一份
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战