設計模式:原型模式

一、引

我們在日常的開發中,可能會遇到需要重複創建相同或者類似的對象,這個時候如果使用實例化(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;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章