原型模式
定义
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
模式的角色和类图
原型模式包含如下角色:
- 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
- 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
- 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
类图
Cloneable接口只是一个标识,接口里面并没有任何方法。真正的clone方法在Object类中。
实现
具体代码如下:
public class User implements Cloneable, Serializable {
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public User(){
System.out.println("原型对象创建完成");
}
@Override
protected User clone() throws CloneNotSupportedException {
return (User)super.clone();
}
public void show(){
System.out.println("用户"+person.getName()+"正在工作!");
}
}
public class Person implements Serializable {
private String name;
public Person(String name){
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
使用测试代码测试:
public class MainTest {
public static void main(String[] args) throws Exception {
User user = new User();
Person person = new Person("张三");
user.setPerson(person);
User user1 = user.clone();
System.out.println(user1 == user);
System.out.println(user1.getPerson() == user.getPerson());
}
}
结果:
原型对象创建完成
false
true
所以使用Obeject中的克隆方法得到的对象时一个新的对象。但是对象中的非基本类型属性是相等的,并没有重新创建。这就引出了原型模式的深拷贝和浅拷贝。
浅拷贝和深拷贝
定义
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
所以如果只是实现Object中的Clone方法后也没有重写,那么就是浅拷贝,对象中非基本类型的属性没有重新创建新对象。如果需要一个新的属性对象。可以重写clone方法。创建新的属性对象。这就是深拷贝。
如实现深拷贝,可将clone方法重写,具体代码如下:
@Override
protected User clone() throws CloneNotSupportedException {
User user = (User)super.clone();
user.setPerson(new Person("新对象"));
return user;
}
测试结果:
原型对象创建完成
false
false
还有一种深拷贝就是通过对象流的方式读取已经写入文件中的对象。在单列模式中我们说到对象流对单列模式的破坏是一个道理。在没有readResovle方法的情况下,对象流读取对象时会返回一个全新的对象,并且是深拷贝后的对象,我们通过代码测试下。
具体代码如下:
public class MainTest {
public static void main(String[] args) throws Exception {
User user = new User();
Person person = new Person("张三");
user.setPerson(person);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\lenovo\\Desktop\\cs.txt"));
oos.writeObject(user);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\lenovo\\Desktop\\cs.txt"));
User user1 = (User)(ois.readObject());
ois.close();
System.out.println(user.getPerson() == user1.getPerson());
user.show();
user1.getPerson().setName("李四");
user1.show();
}
}
结果:
原型对象创建完成
false
用户张三正在工作!
用户李四正在工作!
上述代码没有调用clone方法。就是通过对象流的readObject(),我们得到的结果是原型对象创建了,并且非基本类型属性也重新创建了。这就是深拷贝。