概述
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
适用性
- 当一个系统应该独立于它的产品创建、构成和表示时
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载
- 为了避免创建一个与产品类层次平行的工厂类层次时
- 当一个类的实例只能有几个不同状态组合中的一种时
原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象
案例
方法一
// 原型
public class Prototype implements Cloneable {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public Object clone(){
try {
return super.clone();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
public class ConcretePrototype extends Prototype {
public ConcretePrototype(String name) {
setName(name);
}
}
public class Test {
public static void main(String[] args) {
Prototype pro = new ConcretePrototype("prototype");
Prototype pro2 = (Prototype)pro.clone();
System.out.println(pro.getName());
System.out.println(pro2.getName());
}
}
// 输出
// prototype
// prototype
方法二
public class Prototype implements Cloneable {
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
}
一个原型类,只需要实现 Cloneable 接口,覆写 clone() 方法,此处 clone() 方法可以改成任意的名称,因为 Cloneable 接口是个空接口,你可以任意定义实现类的方法名,如 cloneA() 或者 cloneB(),因为此处的重点是 super.clone() 这句话,super.clone() 调用的是 Object 的 clone() 方法,而在 Object 类中 clone() 是 native 的
关于浅拷贝和深拷贝
- 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的
- 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底
// 要实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象
public class Prototype implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String string;
private SerializableObject obj;
/* 浅复制 */
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
/* 深复制 */
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();
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
public SerializableObject getObj() {
return obj;
}
public void setObj(SerializableObject obj) {
this.obj = obj;
}
}
class SerializableObject implements Serializable {
private static final long serialVersionUID = 1L;
}