原型模式屬於對象的建立模式。經過給出一個原型對象來指明全部建立的對象的類型,而後用複製這個原型對象的辦法建立出更多同類型的對象。
原型模式要求對象實現一個能夠「克隆」自身的接口,這樣就能夠經過複製一個實例對象自己來建立一個新的實例。這樣一來,經過原型實例建立新的對象,就再也不須要關心這個實例自己的類型,只要實現了克隆自身的方法,就能夠經過這個方法來獲取新的對象,而無須再去經過new來建立。java
原型模式有淺度clone和深度clone之分(我的理解)。下面我就用一個例子來闡述二者的區別ide
首先建立一個實體類WordDocment讓它實現Cloneable,並重寫clone方法。代碼以下測試
public class WordDocment implements Cloneable{ private String mText="測試"; private List<String> mImages=new ArrayList<String>(); public WordDocment(){ System.out.println("WordDocment"); } @Override protected WordDocment clone() throws CloneNotSupportedException { WordDocment docment=(WordDocment) super.clone(); docment.mImages= this.mImages; docment.mText=this.mText; return docment; } public String getmText() { return mText; } public void setmText(String mText) { this.mText = mText; } public List<String> getmImages() { return mImages; } public void setmImages(List<String> mImages) { this.mImages = mImages; } public void add(String text){ mImages.add(text); } }
而咱們執行的代碼就很簡單了this
public static void main(String[] args) { //獲取原對象並打印 WordDocment docment=new WordDocment(); docment.add("test1"); docment.add("test2"); docment.add("test3"); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); System.out.println(docment.getmText()); for (String string : docment.getmImages()) { System.out.println(string); } System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); try { //clone對象WordDocment WordDocment clone = docment.clone(); clone.setmText("asdf"); clone.add("test4"); clone.add("test5"); clone.add("test6"); System.out.println("???????????????????????????????"); System.out.println(clone.getmText()); for (String string : clone.getmImages()) { System.out.println(string); } System.out.println("???????????????????????????????"); //原對象打印 System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); System.out.println(docment.getmText()); for (String string : docment.getmImages()) { System.out.println(string); } System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); System.out.println(docment.equals(clone)); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
從以上代碼咱們不難看出,clone的方法很簡單。雖然如此,可是咱們仍是須要理清WordDocment與Cloneable和main方法三者的關係(其實也是原形模式中的一種關係表)code
在原形模式中有三個角色:對象
(1)客戶(Client)角色:客戶類提出建立對象的請求。接口
(2)抽象原型(Prototype)角色:這是一個抽象角色,一般由一個Java接口或Java抽象類實現。此角色給出全部的具體原型類所需的接口。get
(3)具體原型(Concrete Prototype)角色:被複制的對象。此角色須要實現抽象的原型角色所要求的接口。原型
關係類圖:string
很明顯,咱們這兒main方法充當了客戶(Client)角色,Cloneable就是抽象原型(Prototype)角色,而WordDocment這個實體類則是咱們的具體原型。
關係弄清楚了以後,咱們再看看運行的結果
結果中看到,WordDocment構造方法只執行了一次,這說明clone只是拷貝了一當前對象,完成了一次備份的工做。可是咱們發如今完成clone以後,給對象中的引用類型的屬性設值,原對象的屬性也發生了改變,這是爲何呢?
緣由其實很簡單,docment.mImages=this.mImages;這句代碼執行的時候只是把this.mImages的引用傳遞給了咱們clone的對象,並無從新開闢空間,這也側面的說明了WordDocment的clone方法只進行了淺度的clone。
那我就想完徹底全的拷貝一個新的對象要怎麼作呢?
其實也很簡單,咱們只須要針對List<String> mImages進行clone就會好的,因而clone的方法裏面就完成了這樣
@Override protected WordDocment clone() throws CloneNotSupportedException { WordDocment docment=(WordDocment) super.clone(); docment.mImages=(List<String>) ((ArrayList<String>) this.mImages).clone(); docment.mText=this.mText; return docment; }
而後咱們再執行測試方法
這兩個類之間就沒用相互影響了,這就是所謂的深度clone
講完了謝謝你們,水平有限,多多包含