原型模式(重要):
當需要多次創建相同或相似對象時,可以複製這個對象。
淺克隆:複製對象本身和基本類型的成員變量(String當做引用類型看待),對於引用類型的成員變量僅複製其引用地址,而引用對象不復制。通過覆蓋Java中的clone()方法來實現淺克隆,淺克隆的對象須實現Cloneable接口。
深克隆:複製對象全部的內容,對於引用類型的成員變量,由於在堆中複製了其引用對象,所以引用地址肯定發生了變化。在Java中,通過序列化的方式實現深克隆。將原有對象寫入流中,寫到流中的對象是原有對象的一個拷貝,然後從流中讀出來實現深克隆,深克隆的對象須實現Serializable接口。
淺克隆與深克隆的區別是引用類型的成員對象是否複製。
原型模式的適用場景:
1.創建新對象的成本過大,需要多次創建相同或相似對象時
2.系統要保存對象的狀態,而對象的狀態變化很小,對象佔用的內存很小,可以使用原型模式配合備忘錄模式來應用。如果對象的狀態變化或佔用的內存很大,可以採用狀態模式。
原型模式的應用:
1.在Struts2中爲了保證線程的安全性,Action對象的創建使用了原型模式,當訪問一個已經存在Action對象時,通過克隆的方式創建一個新對象,從而保證對象中定義的變量無須進行加鎖而實現同步。
原型模式的優點:
1.簡化對象的創建過程,提高對象的創建效率
2.由於克隆方法在原型類的內部,因此增加新的原型類不需要修改原有代碼
3.可以使用深克隆保存對象的狀態
原型模式的缺點:
1.當要克隆已有的類時,需要修改原有代碼,違背了開閉原則
2.實現深克隆需要編寫較爲複雜的代碼
原型模式的例子:
要克隆的對象
public class Student implements Cloneable,Serializable{
private String stuName;
private int stuAge;
private School school;
/**
*
* @Description: 淺克隆,需要實現Cloneable接口
* @author doudou
* @date 2019年10月8日
* @return
* @throws
* @return
* @see java.lang.Object#clone()
*/
public Object clone() {
Student student = null;
try {
student = (Student) super.clone();
} catch (Exception e) {
System.out.println("Clone failure");
}
return student;
}
/**
*
* @Description: 深克隆
* @author doudou
* @date 2019年10月8日
* @return
* @throws IOException
* @throws ClassNotFoundException
* @throws
* @return
*/
public Object deepClone() throws IOException, ClassNotFoundException {
//將對象寫入流中
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);
//將對象從流中取出
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return objectInputStream.readObject();
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getStuAge() {
return stuAge;
}
public void setStuAge(int stuAge) {
this.stuAge = stuAge;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
}
public class School implements Serializable{
}
測試類:
public class Main {
public static void main(String[] args) throws ClassNotFoundException, IOException {
Student student = new Student();
School school = new School();
student.setSchool(school);
student.setStuAge(10);
student.setStuName("doudou");
Student shallowClone = (Student) student.clone();
Student deepClone = (Student) student.deepClone();
System.out.println("student:"+student.toString());
System.out.println("shallowClone:"+(shallowClone.toString()));
System.out.println("shallowClone==student?"+(shallowClone==student));
System.out.println("shallowClone.equals(student)?"+(shallowClone.equals(student)));
System.out.println("shallowClone.getStuName()==student.getStuName()?"+(shallowClone.getStuName()==student.getStuName()));
System.out.println("deepClone:"+(deepClone.toString()));
System.out.println("deepClone==student?"+(deepClone==student));
System.out.println("deepClone.equals(student)?"+(deepClone.equals(student)));
System.out.println("deepClone.getStuName()==student.getStuName()?"+(deepClone.getStuName()==student.getStuName()));
}
}