1.原型模式
原型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。当创建给定类的实例的过程很昂贵或很复杂时,就使用原型模式。
原型模式就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。
2.浅复制和深复制
所谓的“浅复制”,即是被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象;对于“深复制”,则把引用对象的变量指向复制过的新对象,而不是原有的被引用对象。详见浅复制和深复制的解析
浅复制与深复制的区别:对象的引用是否仍然指向原来的对象。
3.原型模式的结构
客户(Client)角色:客户类提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
Prototype类,抽象原型
public interface Prototype{
/**
* 克隆自身的方法
* @return 一个从自身克隆出来的对象
*/
public Object clone();
}
ConcretePrototype类,具体原型类
public class ConcretePrototype implements Prototype {
//简易克隆,新建一个克隆对象
public Object clone(){
Prototype prototype = new ConcretePrototype();
return prototype;
}
}
使用Java的clone()方法实现对象的克隆,需实现Cloneable接口,Cloneable是标识接口,可不实现重写。
public class ConcretePrototype2 implements Cloneable {
//若要重写clone方法
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
注意:当克隆对象包含着对其他对象的引用时,需要重写其对象的clone()方法
4.clone()和序列化
I. clone()
示例为直线对象,直线上有左右两个点对象的引用
点对象
public class Node implements Cloneable {
private boolean flag;
private int Xpos;
private int Ypos;
private int grade; //顶点的值
public Node(){} //无参构造函数
//setter和getter及其他方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
线对象
public class Line implements Cloneable {
private boolean flag;
private Node Lnode;
private Node Rnode;
private char operator; //运算符
public Line(){}
//setter和getter及其他方法
@Override
protected Object clone() throws CloneNotSupportedException {
Line line = (Line) super.clone();
//对引用的对象也进行复制
line.Lnode = (Node) Lnode.clone();
line.Rnode = (Node) Rnode.clone();
return line;
}
}
II. 序列化及反序列化
为实现序列化,所有需要复制的对象都需要实现java.io.Serializable接口。
public Object deepClone() throws IOException, ClassNotFoundException{
//将对象写到流里
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//从流里读回来
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
对容器的序列化(容器内对象需实现Serializable)
public ArrayList deepCopy(ArrayList src) throws IOException, ClassNotFoundException{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in =new ObjectInputStream(byteIn);
ArrayList dest = (ArrayList)in.readObject();
return dest;
}
5.总结
I. 一般在初始化的信息不发生变化的情况下,克隆是最好的办法。这既隐藏了对象创建的细节,又对性能有所提高。
II. 不需重新初始化对象,而是动态地获得对象运行时的状态。
III. 向客户隐藏制造新示例的复杂性。
参考资料:
1.《Head Frist设计模式》
2.《大话设计模式》