一、引
我們在日常的開發中,可能會遇到需要重複創建相同或者類似的對象,這個時候如果使用實例化(new),那麼我們需要多少個對象,就需要實例化多少次,這不僅會導致代碼重複的災難,還難以對已實例化的對象進行修改,那麼這個時候就需要一種設計思想,在需要對象的時候,儘量避免實例化,優化程序結構,且方便我們進行修改,這種模式就是原型模式,可以理解爲利用原型進行復制。
二、問題
有一個簡歷的類(Resume),現在需要多份簡歷,如果通過一份簡歷複製多份?
三、理解及實現
這個時候有人會說,這還不簡單new一個類,然後不斷的賦值就好了,像下列這樣:
Resume a = new Resume();
Resume b = a;
Resume c = b;
會這樣寫的,說明基礎還不夠紮實,因爲,java中對象的單純賦值,並不是複製一個新的對象,而是引用,所以要注意了,不能這麼寫,那麼要怎麼寫呢?思路很簡單,我們需要先實例化一個對象,然後通過這個對象複製(結構+數據)出無數的新對象,這樣每個對象都是獨立的,而且還能在原對象數據的基礎上進行更改,方便很多,說起來容易,我們要怎麼做呢?我們先來看看原型模式的結構圖:
從圖中我們可以理解到,需要定義一個原型抽象類,這個類有一個克隆的接口,一般在實體類的這個接口中,使用克隆方法進行克隆,但是由於克隆實在是太常用了,所以java早就給我們定義好了這個抽象類(Cloneable),所以我們的實體類直接實現這個接口就行了。具體代碼如下:
public class Resume implements Cloneable {
private String name;
private String sex;
private int age;
private WorkExperience workExperience;
public Resume(String name) {
this.name = name;
workExperience = new WorkExperience();
}
public void setName(String name) {
this.name = name;
}
public void setPersonal(String sex, int age) {
this.age = age;
this.sex = sex;
}
public void setWork(String timeArea, String company) {
workExperience.timeArea = timeArea;
workExperience.company = company;
}
@Override
public Resume clone() throws CloneNotSupportedException {
return (Resume)super.clone();
}
public void display() {
System.out.println(this.name + " " + this.sex + " " + this.age + " " + this.sex);
System.out.print("Work experience: " + this.workExperience.timeArea);
System.out.println(" " + this.workExperience.company);
}
}
public class WorkExperience {
public String timeArea = null;
public String company = null;
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Resume resume1 = new Resume("Jobs");
resume1.setPersonal("Male", 26);
resume1.setWork("2016年8月1日 - 2018年6月30日", "Huawei");
Resume resume2 = resume1.clone();
resume2.setName("Tom");
resume2.setWork("2018年7月1日 - 2019年1月10日", "Baidu");
resume1.display();
resume2.display();
}
}
運行之後,你會發現一件很奇怪的事情,就是名字正常的更改了,但兩個對象的工作經歷都變成了最後一次更改時的值,這是怎麼回事呢?這就涉及到了淺複製和深複製的概念。因爲clone這個方法,對於值類型的屬性進行逐位複製,但對於引用的對象,只複製引用而不復制引用的對象,所以,在例子中WorkExperience是被引用的對象,所以例子中的兩個對象都在對一個WorkExperience實例進行修改,纔會導致以上的問題,這就是淺複製,那麼我們如何進行深複製呢?我們在clone進行操作就行,代碼如下:
@Override
public Resume clone() throws CloneNotSupportedException {
int age = this.age;
String sex = this.sex;
String name = new String(this.name);
Resume copy = new Resume(name, famMem);
copy.setPersonal(sex, age);
copy.setWork(this.work.timeArea, this.work.company);
return copy;
}