原型模式是一種簡單、易使用的創(chuàng)建型設計模式,通過給出一個原型對象來指明所創(chuàng)建的對象的類型,然后用復制這個原型對象的辦法創(chuàng)建出更多同類型的對象臂寝。原型模式要求對象實現(xiàn)一個可以“克隆”自身的接口,這樣就可以通過復制一個實例對象本身來創(chuàng)建一個新的實例摊灭。這樣一來交煞,通過原型實例創(chuàng)建新的對象,就不再需要關心這個實例本身的類型斟或,只要實現(xiàn)了克隆自身的方法素征,就可以通過這個方法來獲取新的對象,而無須再去通過new來創(chuàng)建萝挤。
原型模式的結構圖如下所示:
原型模式的參與角色:
(1)客戶角色:客戶類提出創(chuàng)建對象的請求御毅。
(2)抽象原型角色:這是一個抽象角色,通常由一個java接口或抽象類實現(xiàn)怜珍,具體原型都需要實現(xiàn)該接口端蛆。
(3)具體原型角色:客戶端所需要的被復制的對象。
下面還是通過代碼描述該模式的具體使用:
1酥泛、第一個文件:抽象原型文件Prototype.java
public abstract class Prototype implements Cloneable {
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
2今豆、第二個文件:具體原型文件ConcretePrototype1.java
public class ConcretePrototype1 extends Prototype {
public static int classFlag = 1;
/**
* 克隆自身方法
*
* @return
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException {
return (ConcretePrototype1) super.clone();
}
}
3嫌拣、第三個文件:具體原型文件ConcretePrototype2.java
public class ConcretePrototype2 extends Prototype {
public static int classFlag = 2;
/**
* 克隆自身方法
*
* @return
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException {
return (ConcretePrototype2) super.clone();
}
}
4、第四個文件:TestMain.java
public class TestMain {
public static void main(String[] args) throws CloneNotSupportedException {
Prototype prototype1 = new ConcretePrototype1();
ConcretePrototype1 concretePrototype1 = (ConcretePrototype1) prototype1.clone();
System.out.println(concretePrototype1.classFlag);
Prototype prototype2 = new ConcretePrototype2();
ConcretePrototype2 concretePrototype2 = (ConcretePrototype2) prototype2.clone();
System.out.println(concretePrototype2.classFlag);
}
}
看了以上代碼呆躲,大家可能會覺得原型模式其實還是挺簡單的异逐。
我們上面描述的對象創(chuàng)建方法是通過調(diào)用java中的clone方法來復制對象,我看到網(wǎng)上還有另外一種使用new的方式來創(chuàng)建對象插掂,具體原型的寫法如下所示灰瞻。
5、第一個文件:Prototype.java
public interface Prototype {
public Object clone();
}
6辅甥、第二個文件:ConcretePrototype1.java
public class ConcretePrototype1 implements Prototype {
@Override
public Object clone() {
// 最簡單的克隆酝润,新建一個自身對象,由于沒有屬性就不再復制值了
Prototype prototype = new ConcretePrototype1();
return prototype;
}
}
7璃弄、第三個文件ConcretePrototype2.java
public class ConcretePrototype2 implements Prototype {
@Override
public Object clone() {
//最簡單的克隆要销,新建一個自身對象,由于沒有屬性就不再復制值了
Prototype prototype = new ConcretePrototype2();
return prototype;
}
}
至于以上兩種寫法的區(qū)別就在于一種是直接調(diào)用clone方法實現(xiàn)淺克隆出一個對象夏块,第二種是使用new蕉陋,創(chuàng)建出一個完完全全獨立的新對象,咱就把它稱作是"深克隆"吧拨扶。
至于淺克隆和深克隆的區(qū)別是什么呢,簡單的說:如果一個對象中只有基本類型屬性茁肠,那深克隆和淺克隆效果都是一樣的患民,基本類型數(shù)據(jù)不管是用深克隆還是淺克隆都會被克隆出一份,但如果對象中包含引用對象屬性垦梆,那淺克隆其實這是拷貝了一份引用匹颤,而深克隆確實把整個引用對象都拷貝了一份。
在看了原型模式之后托猩,大家可能會覺得這個跟工廠模式比較的相似印蓖。咱們把工廠模式的結構圖也畫一下,大家對比一下就知道的區(qū)別了京腥。
比較明顯原型模式?jīng)]有工廠模式的抽象工廠和具體工廠的實現(xiàn)赦肃,代碼結構要簡單一些,當然你也可以把原型模式的抽象原型理解成一種特殊的工廠公浪。
8他宛、原型模式的優(yōu)點:
(1)根據(jù)客戶端要求實現(xiàn)動態(tài)創(chuàng)建對象,客戶端不需要知道對象的創(chuàng)建細節(jié)欠气,便于代碼的維護和擴展厅各。
(2)使用原型模式創(chuàng)建對象比直接new一個對象在性能上要好的多,因為Object類的clone方法是一個本地方法预柒,它直接操作內(nèi)存中的二進制流队塘,特別是復制大對象時袁梗,性能的差別非常明顯。所以在需要重復地創(chuàng)建相似對象時可以考慮使用原型模式憔古。比如需要在一個循環(huán)體內(nèi)創(chuàng)建對象遮怜,假如對象創(chuàng)建過程比較復雜或者循環(huán)次數(shù)很多的話,使用原型模式不但可以簡化創(chuàng)建過程投放,而且可以使系統(tǒng)的整體性能提高很多奈泪。
(3) 原型模式類似于工廠模式,但它沒有了工廠模式中的抽象工廠和具體工廠的層級關系灸芳,代碼結構更清晰和簡單涝桅。
9、原型模式的注意事項:
(1)使用原型模式復制對象不會調(diào)用類的構造方法烙样。因為對象的復制是通過調(diào)用Object類的clone方法來完成的冯遂,它直接在內(nèi)存中復制數(shù)據(jù),因此不 會調(diào)用到類的構造方法谒获。不但構造方法中的代碼不會執(zhí)行蛤肌,甚至連訪問權限都對原型模式無效。還記得單例模式嗎批狱?單例模式中裸准,只要將構造方法的訪問權限設置為 private型,就可以實現(xiàn)單例赔硫。但是clone方法直接無視構造方法的權限炒俱,所以,單例模式與原型模式是沖突的爪膊。
(2)在使用時要注意深拷貝與淺拷貝的問題权悟。clone方法只會拷貝對象中的基本的數(shù)據(jù)類型,對于數(shù)組推盛、容器對象峦阁、引用對象等都不會拷貝,這就是淺拷貝耘成。如果要實現(xiàn)深拷貝榔昔,必須將原型模式中的數(shù)組、容器對象瘪菌、引用對象等另行拷貝件豌。