版權聲明:轉載必須註明本文轉自曉_晨的博客:http://blog.csdn.net/niunai112
目錄
導航
設計模式之六大設計原則
設計模式(一)單例模式
設計模式(二)工廠模式
設計模式(三)策略模式
設計模式(四)適配器模式
設計模式(五)享元模式
設計模式(六)建造者模式
設計模式(七)原型模式
設計模式(八)橋接模式
設計模式(九)外觀模式
設計模式(十)組合模式
設計模式(十一)裝飾器模式
設計模式(十二)代理模式
設計模式(十三)迭代器模式
設計模式(十四)觀察者模式
設計模式(十五)中介者模式
設計模式(十六)命令模式
設計模式(十七)狀態模式
設計模式(十八)訪問者模式
設計模式(十九)責任鏈模式
設計模式(二十)解釋器模式
設計模式(二十一)備忘錄模式
設計模式(二十二)模板模式
設計模式總結篇(爲什麼要學習設計模式,學習設計模式的好處)
前言
原型模式:用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。被複制的實例被稱爲原型,這個原型是可定製的。
在Java中,jdk提供了語言級的支持,只要對象實現了Cloneable接口,重寫clone方法,即可賦值對象。但在賦值對象中要注意淺層複製與深層複製的區別。LZ會在接下來的例子中講清楚。
例子
在一個遊戲中,假如我們需要創建大量的士兵的話,傳統的方法是我們需要不停的new出來對象,但是假如new對象的創建過程非常耗時的話,那麼我們就要花費大量的時間在創建對象上了,那這部分時間我們能不能省下來呢?答案就在原型模式上。
淺層複製,對於複製出來的對象字段是引用已有的內存空間
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 14:27 2018/3/21
*@Modified By:
*
*/
public class Soldier implements Cloneable{
Integer hp;
int mp;
String name;
DeepCopy deepCopy;
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 10:24 2018/3/21
*@Modified By:
*
*/
public class Test {
public static void main(String[] args) {
Soldier soldier = new Soldier();
soldier.hp = new Integer(5000);
soldier.mp = 1;
soldier.name = "1";
soldier.deepCopy = new DeepCopy();
soldier.deepCopy.attribute1 = "attribute1";
Soldier cloneSoldier = (Soldier)soldier.clone();
System.out.println("原始士兵的deepCopy的attribute1的值:" + soldier.deepCopy.attribute1);
System.out.println("克隆對象的deepCopy的attribute1的值:" + cloneSoldier.deepCopy.attribute1);
cloneSoldier.deepCopy.attribute1 = "changeAttribute";
System.out.println("修改克隆對象的deepCopy的attribute1的值後,原始士兵的deepCopy的attribute1值:" + soldier.deepCopy.attribute1);
System.out.println("修改克隆對象的deepCopy的attribute1的值後,克隆對象的deepCopy的attribute1值:" + cloneSoldier.deepCopy.attribute1);
}
}
運行結果如下
--------------------------
原始士兵的deepCopy的attribute1的值:attribute1
克隆對象的deepCopy的attribute1的值:attribute1
修改克隆對象的deepCopy的attribute1的值後,原始士兵的deepCopy的attribute1值:changeAttribute
修改克隆對象的deepCopy的attribute1的值後,克隆對象的deepCopy的attribute1值:changeAttribute
UML圖
深層克隆,對於複製出來的對象字段也複製一個新的空間,並引用到新的空間。
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 10:23 2018/3/21
*@Modified By:
*
*/
public class Soldier implements Cloneable{
public Integer hp;
public int mp;
public String name;
public DeepCopy deepCopy;
public Object clone() {
Object clone = null;
Soldier clone1 = null;
try {
clone = super.clone();
clone1 = (Soldier) clone;
clone1.deepCopy = (DeepCopy) this.deepCopy.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone1;
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 10:44 2018/3/21
*@Modified By:
*
*/
public class DeepCopy implements Cloneable{
public String attribute1;
public String attribute2;
public DeepCopy(){
for (int i = 0; i < 10000; i++){
this.attribute1 = "" + i;
}
}
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
public class Test {
public static void main(String[] args) {
Soldier soldier = new Soldier();
soldier.hp = new Integer(5000);
soldier.mp = 1;
soldier.name = "1";
soldier.deepCopy = new DeepCopy();
soldier.deepCopy.attribute1 = "attribute1";
Soldier cloneSoldier = (Soldier)soldier.clone();
System.out.println("原始士兵的deepCopy的attribute1的值:" + soldier.deepCopy.attribute1);
System.out.println("克隆對象的deepCopy的attribute1的值:" + cloneSoldier.deepCopy.attribute1);
cloneSoldier.deepCopy.attribute1 = "changeAttribute";
System.out.println("修改克隆對象的deepCopy的attribute1的值後,原始士兵的deepCopy的attribute1值:" + soldier.deepCopy.attribute1);
System.out.println("修改克隆對象的deepCopy的attribute1的值後,克隆對象的deepCopy的attribute1值:" + cloneSoldier.deepCopy.attribute1);
}
}
運行結果如下
---------------------------------------
原始士兵的deepCopy的attribute1的值:attribute1
克隆對象的deepCopy的attribute1的值:attribute1
修改克隆對象的deepCopy的attribute1的值後,原始士兵的deepCopy的attribute1值:attribute1
修改克隆對象的deepCopy的attribute1的值後,克隆對象的deepCopy的attribute1值:changeAttribute
這樣修改裏面的屬性就不會影響到原始對象了,clone多個也不會相互影響。
對比
這裏專門新建了一個原型模式比新建對象快多少的測試模型
public class Soldier implements Cloneable{
public Integer hp;
public int mp;
public String name;
public DeepCopy deepCopy;
public Object clone() {
Object clone = null;
Soldier clone1 = null;
try {
clone = super.clone();
clone1 = (Soldier) clone;
clone1.deepCopy = (DeepCopy) this.deepCopy.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone1;
}
}
public class DeepCopy implements Cloneable{
public String attribute1;
public String attribute2;
public DeepCopy(){
}
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 10:24 2018/3/21
*@Modified By:
*
*/
public class Test {
public static void main(String[] args) {
Soldier soldier = new Soldier();
soldier.hp = 1;
soldier.mp = 1;
soldier.name = "1";
soldier.deepCopy = new DeepCopy();
long begin = System.currentTimeMillis();
for (int i = 0; i < 10000; i++){
Soldier soldier1 = new Soldier();
soldier1.deepCopy = new DeepCopy();
}
long end = System.currentTimeMillis();
System.out.println("新建10000個對象耗時:" + (end - begin));
begin = System.currentTimeMillis();
for (int i = 0; i < 10000; i++){
soldier.clone();
}
end = System.currentTimeMillis();
System.out.println("克隆10000個對象耗時:" + (end - begin));
}
}
運行結果如下
-----------------------------------------
新建10000個對象耗時:1
克隆10000個對象耗時:3
是不是覺得很奇怪,用了原型模式反而變慢了?不要急,我們在DeepCopy裏的默認構造方法裏假如for循環來模擬耗時操作
/***
*
*@Author ChenjunWang
*@Description:
*@Date: Created in 10:44 2018/3/21
*@Modified By:
*
*/
public class DeepCopy implements Cloneable{
public String attribute1;
public String attribute2;
public DeepCopy(){
for (int i = 0; i < 10000; i++){
this.attribute1 = "" + i;
}
}
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
運行結果如下
---------------------------
新建10000個對象耗時:1791
克隆10000個對象耗時:2
好了,大家應該可以看出差距了吧,因爲克隆對象不需要調用新建對象的構造函數,而是直接用對內存進行復制的操作,所以,構造函數越耗時,那麼用原型模式的收益就越高。而假如構造函數不復雜,那麼使用原型模式會略微增加一點性能消耗,但是相比第二個對比的收益來說,原型模式增加一點性能消耗根本微乎其微。
總結
原型模式的Prototype類必須繼承Cloneable接口,並對接口中的clone方法進行實現,主要的優點與缺點如下:
優點
(1):使用原型模型創建一個對象比直接new一個對象更有效率,因爲它直接操作內存中的二進制流,特別是複製大對象時,性能的差別非常明顯。
(2):隱藏了製造新實例的複雜性,使得創建對象就像我們在編輯文檔時的複製粘貼一樣簡單。
缺點
(1):需要爲每一個類配置一個克隆方法,而且該克隆方法位於類的內部,當對已有類進行改造的時候,需要修改代碼,違反了開閉原則。
(2):在實現深克隆時需要編寫較爲複雜的代碼,爲了實現深克隆,每一層對象對應的類都必須支持深克隆,實現起來會比較麻煩。
Git地址
本篇實例Github地址:https://github.com/stackisok/Design-Pattern/tree/master/src/prototype
有什麼不懂或者不對的地方,歡迎留言。
喜歡LZ文章的小夥伴們,可以關注一波,也可以留言,LZ會回你們的。
覺得寫得不錯的小夥伴,歡迎轉載,但請附上原文地址,謝謝^_^!