一、定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
优点:原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
tips:逃避构造函数的约束,直接在内存中拷贝,构造函数是不会执行的,这既是它的优点也是缺点。
二、实现
public class Client {
public static void main(String[] args) {
PrototypeClass prototypeClass = new PrototypeClass();
//对象拷贝时构造函数确实没有被执行,Object类的clone方法的
// 原理是从内存中(具体地说就是堆内存)以二进制流的方式进行拷贝,重新分配一个内存块
System.out.println("准备克隆...");
PrototypeClass prototypeClass1 = prototypeClass.clone();
System.out.println("克隆完成...");
}
}
class PrototypeClass implements Cloneable{
public PrototypeClass() {
System.out.println("执行构造函数中...");
}
//覆写父类Object方法
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass)super.clone();
} catch (CloneNotSupportedException e) {
//异常处理
}
return prototypeClass;
}
}
三、浅拷贝和深拷贝
- 浅拷贝:Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。此时,其中一个对象的改变都会影响到另一个对象。
使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象(如String)。
public class Client {
public static void main(String[] args) {
PrototypeClass prototypeClass = new PrototypeClass();
prototypeClass.setValue("Hello");
System.out.println("prototypeClass值:" + prototypeClass.getValue());
//对象拷贝时构造函数确实没有被执行,Object类的clone方法的
// 原理是从内存中(具体地说就是堆内存)以二进制流的方式进行拷贝,重新分配一个内存块
System.out.println("准备克隆...");
PrototypeClass prototypeClass1 = prototypeClass.clone();
prototypeClass1.setValue("world");
System.out.println("prototypeClass1值:" + prototypeClass1.getValue());
System.out.println("克隆完成...");
prototypeClass1.setValue("java");
System.out.println("prototypeClass值:" + prototypeClass.getValue());
}
}
class PrototypeClass implements Cloneable{
//定义一个私有变量
private ArrayList<String> arrayList = new ArrayList<>();
public PrototypeClass() {
System.out.println("执行构造函数中...");
}
//覆写父类Object方法
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass)super.clone();
} catch (CloneNotSupportedException e) {
//异常处理
}
return prototypeClass;
}
//设置arrayList的值
public void setValue(String value){
this.arrayList.add(value);
}
//取得arrayList的值
public ArrayList<String> getValue(){
return this.arrayList;
}
}
- 深拷贝:拷贝一个对象时,不仅仅把对象的引用进行复制,还把该对象引用的值也一起拷贝。这样进行深拷贝后的拷贝对象就和源对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
实现1:除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。要使用clone方法,类的成员变量上不要增加final关键字。
class Client {
public static void main(String[] args) {
PrototypeClass prototypeClass = new PrototypeClass();
prototypeClass.setValue("Hello");
System.out.println("prototypeClass值:" + prototypeClass.getValue());
//对象拷贝时构造函数确实没有被执行,Object类的clone方法的
// 原理是从内存中(具体地说就是堆内存)以二进制流的方式进行拷贝,重新分配一个内存块
System.out.println("准备克隆...");
PrototypeClass prototypeClass1 = prototypeClass.clone();
prototypeClass1.setValue("world");
System.out.println("prototypeClass1值:" + prototypeClass1.getValue());
System.out.println("克隆完成...");
System.out.println("prototypeClass值:" + prototypeClass.getValue());
}
}
class PrototypeClass implements Cloneable{
//定义一个私有变量
private ArrayList<String> arrayList = new ArrayList<>();
public PrototypeClass() {
System.out.println("执行构造函数中...");
}
//覆写父类Object方法
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass)super.clone();
prototypeClass.arrayList = (ArrayList<String>) this.arrayList.clone();
} catch (CloneNotSupportedException e) {
//异常处理
}
return prototypeClass;
}
//设置arrayList的值
public void setValue(String value){
this.arrayList.add(value);
}
//取得arrayList的值
public ArrayList<String> getValue(){
return this.arrayList;
}
}
tips:如果在拷贝一个对象时,要想让这个拷贝的对象和源对象完全彼此独立,那么在引用链上的每一级对象都要被显式的拷贝。所以创建彻底的深拷贝是非常麻烦的,尤其是在引用关系非常复杂的情况下, 或者在引用链的某一级上引用了一个第三方的对象, 而这个对象没有实现clone方法, 那么在它之后的所有引用的对象都是被共享的。
实现2:将对象序列化为字节序列后,默认会将该对象的整个对象图进行序列化,再通过反序列即可完美地实现深拷贝。
public class Client {
public static void main(String[] args) throws IOException, ClassNotFoundException {
PrototypeClass prototypeClass = new PrototypeClass();
prototypeClass.setValue(new Person("小明", 12));
//通过序列化方法实现深拷贝
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(prototypeClass);
oos.flush();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
PrototypeClass prototypeClass1 = (PrototypeClass) ois.readObject();
prototypeClass1.setValue(new Person("小红", 10));
System.out.println("prototypeClass值:" + prototypeClass.getValue());
System.out.println("prototypeClass1值:" + prototypeClass1.getValue());
}
}
class PrototypeClass implements Serializable{
//定义一个私有变量
private ArrayList<Person> arrayList = new ArrayList<>();
public PrototypeClass() {
System.out.println("执行构造函数中...");
}
//设置arrayList的值
public void setValue(Person value){
this.arrayList.add(value);
}
//取得arrayList的值
public ArrayList<Person> getValue(){
return this.arrayList;
}
}
class Person implements Serializable{
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}