原型模式概念
使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式分为浅克隆方式和深克隆方式,浅克隆通过实现Cloneable接口、并实现Object的clone()方法实现,深克隆通过序列化机制实现。
浅克隆原型模式结构图
实现Cloneable接口,并实现Object的clone()方法:
浅克隆原型模式角色介绍
抽象原型角色:Object,作为所有类的默认父类,无需主动继承,它声明了克隆方法的接口。
原型角色:它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
可克隆标志角色:Cloneable,一个空接口,原型角色需要实现该接口,才能具有克隆自己的能力。如果不实现Cloneable接口,则无法克隆自己,调用clone()方法时抛出CloneNotSupportedException异常。
客户端角色:Client,持有原型对象实例,通过原型对象调用自己的克隆方法,获取原型对象的克隆对象。
浅克隆原型模式结构代码
Object:
protected native Object clone() throws CloneNotSupportedException;
Cloneable:
public interface Cloneable {
}
Prototype:
public class Prototype implements Cloneable{
private Attribute attribute;
public Attribute getAttribute() {
return attribute;
}
public void setAttribute(Attribute attribute) {
this.attribute = attribute;
}
//实现克隆方法
public Prototype clone() {
Prototype prototype = null;
try {
//调用父类clone方法
prototype = (Prototype)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return prototype;
}
}
class Attribute {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Attribute(String name) {
this.name = name;
}
}
Client:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Attribute attribute1 = new Attribute("attribute1");
Prototype prototype1 = new Prototype();
prototype1.setAttribute(attribute1);
Attribute attribute2 = new Attribute("attribute2");
Prototype prototype2 = (Prototype) prototype1.clone();
//判断原型对象和克隆对象是否是同一个对象,false,不是同一个,实现了克隆
System.out.println(prototype1 == prototype2);//false
//判断克隆对象的引用成员变量与原型对象的引用成员变量是否是同一个对象,结果为true,是同一个对象,引用成员变量未实现克隆
System.out.println(prototype2.getAttribute()==prototype1.getAttribute());//true
}
}
浅克隆原型模式运行机制
原型类实现cloneable接口,表示该原型类是支持克隆的;实现clone()接口,内部调用super.clone(),克隆自己并返回。
浅克隆只能实现原型对象本身和内部基本类型成员变量的克隆,对于引用类型成员变量,只是对引用成员变量指向对象的地址进行克隆,并不能对引用成员变量指向的对象本身进行克隆,要实现引用类型成员变量指向的对象本身克隆,需要采用序列化机制的深克隆方式。
深克隆原型模式结构图
深克隆原型模式角色介绍
可序列化角色:Serializable,可序列化标志空接口,实现该接口,才能被序列化。原型对象和原型对象内部引用类型成员属性都需要实现该接口。
原型对象角色:Prototype,需要被克隆的对象,普通bean,需要实现Serializable接口。
属性对象:Attribute,原型对象内部引用类型成员变量类型,随着原型对象的克隆一起呗克隆,需要实现Serializable接口。
深克隆原型模式结构代码
Prototype:
public class Prototype implements Serializable {
private Attribute attribute;
public Attribute getAttribute() {
return attribute;
}
public void setAttribute(Attribute attribute) {
this.attribute = attribute;
}
//序列化实现深克隆
public Prototype 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 (Prototype)ois.readObject();
}
}
Attribute:
class Attribute implements Serializable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Attribute(String name) {
this.name = name;
}
}
Client:
public class Client {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Attribute attribute1 = new Attribute("attribute1");
Prototype prototype1 = new Prototype();
prototype1.setAttribute(attribute1);
Attribute attribute2 = new Attribute("attribute2");
Prototype prototype2 = prototype1.deepClone();
//判断原型对象和克隆对象是否是同一个对象,false,不是同一个,实现了克隆
System.out.println(prototype1 == prototype2);//false
//判断克隆对象的引用成员变量与原型对象的引用成员变量是否是同一个对象,结果为false,实现了深克隆
System.out.println(prototype2.getAttribute()==prototype1.getAttribute());//false
}
}
深克隆原型模式运行机制
1、所有克隆的对象实现Serializable接口,包括克隆对象及其引用类型成员变量对象;
2、通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。
原型模式解决的核心问题
采用原型模式实现克隆机制,达到降低对象创建成本、保持对象状态、隐藏创建过程的目的。