代码托管
“通过复制一个原型对象得到多个与原型对象一模一样的新对象
定义:
“原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。
原型模式的结构
原型模式包含以下3个角色:
浅克隆与深克隆
浅克隆(Shallow Clone):当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
**深克隆(Deep Clone):**除了对象本身被复制外,对象所包含的所有成员变量也将被复制。
通用的克隆实现方法
Java语言中的clone()方法和Cloneable接口
在Java语言中,提供了一个clone()方法用于实现浅克隆,该方法使用起来很方便,直接调用super.clone()方法即可实现克隆
浅克隆
WeeklyLog.java
package com.nateshao.prototype.shallowclone;
public class WeeklyLog implements Cloneable {
// 为了简化设计和实现,假设一份工作周报中只有一个附件对象,
// 实际情况中可以包含多个附件,可以通过List等集合对象来实现
private Attachment attachment;
private String name;
private String date;
private String content;
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
public void setName(String name) {
this.name = name;
}
public void setDate(String date) {
this.date = date;
}
public void setContent(String content) {
this.content = content;
}
public Attachment getAttachment() {
return (this.attachment);
}
public String getName() {
return (this.name);
}
public String getDate() {
return (this.date);
}
public String getContent() {
return (this.content);
}
//使用clone()方法实现浅克隆
public WeeklyLog clone() {
Object obj = null;
try {
obj = super.clone();
return (WeeklyLog)obj;
}
catch(CloneNotSupportedException e) {
System.out.println("不支持复制!");
return null;
}
}
}
Attachment.java
package com.nateshao.prototype.shallowclone;
public class Attachment {
private String name; //附件名
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void download() {
System.out.println("下载附件,文件名为" + name);
}
}
Client.java
package com.nateshao.prototype.shallowclone;
public class Client {
public static void main(String args[]) {
WeeklyLog log_previous, log_new;
log_previous = new WeeklyLog(); //创建原型对象
Attachment attachment = new Attachment(); //创建附件对象
log_previous.setAttachment(attachment); //将附件添加到周报中
log_new = log_previous.clone(); //调用克隆方法创建克隆对象
//比较周报
System.out.println("周报是否相同? " + (log_previous == log_new));
//比较附件
System.out.println("附件是否相同? " + (log_previous.getAttachment() == log_new.getAttachment()));
}
}
深克隆
WeeklyLog.java
package com.nateshao.prototype.deepclone;
import java.io.*;
/**
* @date Created by 邵桐杰 on 2021/10/14 21:59
* @微信公众号 程序员千羽
* @个人网站 www.nateshao.cn
* @博客 https://nateshao.gitee.io
* @GitHub https://github.com/nateshao
* @Gitee https://gitee.com/nateshao
* Description:
*/
public class WeeklyLog implements Serializable {
private Attachment attachment;
private String name;
private String date;
private String content;
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
public void setName(String name) {
this.name = name;
}
public void setDate(String date) {
this.date = date;
}
public void setContent(String content) {
this.content = content;
}
public Attachment getAttachment() {
return (this.attachment);
}
public String getName() {
return (this.name);
}
public String getDate() {
return (this.date);
}
public String getContent() {
return (this.content);
}
//使用序列化技术实现深克隆
public WeeklyLog deepClone() throws IOException, ClassNotFoundException, OptionalDataException {
//将对象写入流中
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
return (WeeklyLog)ois.readObject();
}
}
Attachment.java
package com.nateshao.prototype.deepclone;
import java.io.Serializable;
/**
* @date Created by 邵桐杰 on 2021/10/14 22:00
* @微信公众号 程序员千羽
* @个人网站 www.nateshao.cn
* @博客 https://nateshao.gitee.io
* @GitHub https://github.com/nateshao
* @Gitee https://gitee.com/nateshao
* Description:
*/
public class Attachment implements Serializable {
private String name; //附件名
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void download() {
System.out.println("下载附件,文件名为" + name);
}
}
Client.java
package com.nateshao.prototype.deepclone;
/**
* @date Created by 邵桐杰 on 2021/10/14 22:00
* @微信公众号 程序员千羽
* @个人网站 www.nateshao.cn
* @博客 https://nateshao.gitee.io
* @GitHub https://github.com/nateshao
* @Gitee https://gitee.com/nateshao
* Description:
*/
public class Client {
public static void main(String args[]) {
WeeklyLog log_previous, log_new = null;
log_previous = new WeeklyLog(); //创建原型对象
Attachment attachment = new Attachment(); //创建附件对象
log_previous.setAttachment(attachment); //将附件添加到周报中
try {
log_new = log_previous.deepClone(); //调用深克隆方法创建克隆对象
}
catch(Exception e) {
System.err.println("克隆失败!");
}
//比较周报
System.out.println("周报是否相同? " + (log_previous == log_new));
//比较附件
System.out.println("附件是否相同? " + (log_previous.getAttachment() == log_new.getAttachment()));
}
}
实例说明
“在使用某OA系统时,有些岗位的员工发现他们每周的工作都大同小异,因此在填写工作周报时很多内容都是重复的,为了提高工作周报的创建效率,大家迫切希望有一种机制能够快速创建相同或者相似的周报,包括创建周报的附件。 试使用原型模式对该OA系统中的工作周报创建模块进行改进。
实例类图
工作周报创建模块结构图:浅克隆
工作周报对象被成功复制,但是附件对象并没有复制,实现了浅克隆
深克隆解决方案
工作周报类WeeklyLog和附件类Attachment实现Serializable接口
修改工作周报类WeeklyLog的clone()方法
周报是否相同?false
附件是否相同?false
工作周报对象和附件对象都成功复制,实现了深克隆
“定义:原型管理器(Prototype Manager)将多个原型对象存储在一个集合中供客户端使用,它是一个专门负责克隆对象的工厂,其中定义了一个集合用于存储原型对象,如果需要某个原型对象的一个克隆,可以通过复制集合中对应的原型对象来获得
结构:
带原型管理器的原型模式
实现
import java.util.*;
public class PrototypeManager {
private Hashtable prototypeTable=new Hashtable(); //使用Hashtable存储原型对象
public PrototypeManager() {
prototypeTable.put("A", new ConcretePrototypeA());
prototypeTable.put("B", new ConcretePrototypeB());
}
public void add(String key, Prototype prototype) {
prototypeTable.put(key,prototype);
}
public Prototype get(String key) {
Prototype clone = null;
clone = ((Prototype) prototypeTable.get(key)).clone(); //通过克隆方法创建新对象
return clone;
}
}
模式优点
模式缺点
模式适用环境