(Prototype)原型模式的Java实现(转)
生活随笔
收集整理的這篇文章主要介紹了
(Prototype)原型模式的Java实现(转)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原型模式(Prototype):用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象。 當我們已經擁有某個得來不易的寶貝時,往往我們會很想再“變”一些出來,即這個寶貝的“復制品”,這種方式簡單又理想,誰都想要學會這項本事。不可能的事情!不過,這種手段在軟件設計中是完全可以實現的,在OO中的原型模式就是這樣基于思想的。 原型模式的適用場景:(摘錄自《設計模式迷你手冊》) 1、當要實例化的類是在運行時刻指定時,例如,通過動態裝載; 2、為了避免創建一個與產品類層次平行的工廠類層次時; 3、當一個類的實例只能有幾個不同狀態組合中的一種時。建立相應數目的原型并克隆它們可能比每次用合適的狀態手工實例化該類更方便一些。 通用類圖如下: 在Java中,原型模式可以很簡單地實現,只要實現Cloneable這個標識性的接口,再覆蓋該接口中的clone()方法,即可“克隆”該實現類的任何一個對象。“克隆”的意思大家都明白,就是原封不動的復制。 由于Java中的最基類Object類中已經實現了Cloneable接口,故我們下面的代碼例子中的會看不到上面類圖中Prototype這個抽象類的影子。 具體代碼如下: 測試結果:
在Java中有個淺拷貝和深拷貝之分,下面再給出個代碼例子。 //原型02,成員變量中包含引用變量,得用深拷貝?
class?ConcretePrototype02?implements?Cloneable {?
??private?String name;?
??private?ArrayList<String> nameList =?new?ArrayList<String>();?
??public?ConcretePrototype02(String name) {?
????this.name = name;?
????this.nameList.add(this.name);?
??}?
??//添加nameList中的對象?
??public?void?setName(String name) {?
????this.nameList.add(name);?
??}?
????
??public?ArrayList<String> getNameList() {?
????return?this.nameList;?
??}?
????
??//覆蓋Object基類中的clone()方法,并擴大該方法的訪問權限,具體化返回本類型?
??public?ConcretePrototype02 clone() {?
????ConcretePrototype02 self =?null;?
????try?{?
??????self = (ConcretePrototype02)?super.clone();?
??????//以下這句是實現深拷貝的關鍵?
//??????self.nameList = (ArrayList<String>) this.nameList.clone();?
????}?catch?(CloneNotSupportedException e) {?
??????e.printStackTrace();?
????}?
????return?self;?
??}?
}?
//測試類?
public?class?Client {?
??public?static?void?main(String[] args) {?
????ConcretePrototype02 prototype02 =?new?ConcretePrototype02("螞蟻 ...");?
????System.out.println(prototype02.getNameList());?
?????
????//通過clone獲得一個拷貝?
????ConcretePrototype02 fromClone02 = prototype02.clone();?
????fromClone02.setName("小螞蟻 ...");?
????System.out.println(fromClone02.getNameList());?
????System.out.println(prototype02.getNameList());?
??}?
} 測試結果:
發現拷貝之后原來的對象持有的ArrayList<String>類型的nameList引用會隨著拷貝得到的fromClone對象執行了setName()方法而改變,這不是我們想要的結果,因為這意味著原型以及拷貝得到的對象共享同一個引用變量,這是線程不安全的。當我們去掉上面clone()方法中被注釋的語句之后再測試,得到結果如下:
結果正確。其實,在Java中使用原型模式Prototype是相當簡單的,只要記住幾點注意點,就可以方便地實現該模式了。由于使用clone()方法來拷貝一個對象是從內存二進制流中進行IO讀寫,所以拷貝得到一個對象是不會執行該對象所對應類的構造函數的。總結如下: 1、構造函數不會被執行; 2、類的成員變量中若有引用類型的變量(數組也是一種對象),默認的clone()并不會對其進行拷貝,需自行提供深拷貝; String類型與int、long、char等基本類型類似,默認地會被拷貝。 總之,Java中原型模式clone()方法對我們隱藏了許多細節,或者說必要操作,它的實現機制涉及到了反射、IO流操作、序列化等,只有弄清楚這一系列的知識才能更深入地理解這些相關的知識點。 //原型01,實現Cloneable接口并覆蓋clone()方法?
class?ConcretePrototype01?implements?Cloneable {?
??private?String name;?
??public?ConcretePrototype01(String name) {?
????this.name = name;?
??}?
????
??public?void?getName() {?
????System.out.println(name);?
??}?
????
??//覆蓋Object基類中的clone()方法,并擴大該方法的訪問權限,具體化返回本類型?
??public?ConcretePrototype01 clone() {?
????ConcretePrototype01 self =?null;?
????try?{?
??????self = (ConcretePrototype01)?super.clone();?
????}?catch?(CloneNotSupportedException e) {?
??????e.printStackTrace();?
????}?
????return?self;?
??}?
}?
//測試類?
public?class?Client {?
??public?static?void?main(String[] args) {?
????ConcretePrototype01 prototype01 =?new?ConcretePrototype01("螞蟻 ...");?
????prototype01.getName();?
?????
????//通過clone獲得一個拷貝?
????ConcretePrototype01 fromClone01 = prototype01.clone();?
????fromClone01.getName();?
??}?
} 文章出處:http://haolloyin.blog.51cto.com/1177454/333442
| 螞蟻?... 螞蟻?... |
class?ConcretePrototype02?implements?Cloneable {?
??private?String name;?
??private?ArrayList<String> nameList =?new?ArrayList<String>();?
??public?ConcretePrototype02(String name) {?
????this.name = name;?
????this.nameList.add(this.name);?
??}?
??//添加nameList中的對象?
??public?void?setName(String name) {?
????this.nameList.add(name);?
??}?
????
??public?ArrayList<String> getNameList() {?
????return?this.nameList;?
??}?
????
??//覆蓋Object基類中的clone()方法,并擴大該方法的訪問權限,具體化返回本類型?
??public?ConcretePrototype02 clone() {?
????ConcretePrototype02 self =?null;?
????try?{?
??????self = (ConcretePrototype02)?super.clone();?
??????//以下這句是實現深拷貝的關鍵?
//??????self.nameList = (ArrayList<String>) this.nameList.clone();?
????}?catch?(CloneNotSupportedException e) {?
??????e.printStackTrace();?
????}?
????return?self;?
??}?
}?
//測試類?
public?class?Client {?
??public?static?void?main(String[] args) {?
????ConcretePrototype02 prototype02 =?new?ConcretePrototype02("螞蟻 ...");?
????System.out.println(prototype02.getNameList());?
?????
????//通過clone獲得一個拷貝?
????ConcretePrototype02 fromClone02 = prototype02.clone();?
????fromClone02.setName("小螞蟻 ...");?
????System.out.println(fromClone02.getNameList());?
????System.out.println(prototype02.getNameList());?
??}?
} 測試結果:
| 拷貝之前的原型:?[螞蟻?...] 拷貝得到的對象:?[螞蟻?...,?小螞蟻?...] 拷貝之后的原型:?[螞蟻?...,?小螞蟻?...] |
| 拷貝之前的原型:?[螞蟻?...] 拷貝得到的對象:?[螞蟻?...,?小螞蟻?...] 拷貝之后的原型:?[螞蟻?...] |
class?ConcretePrototype01?implements?Cloneable {?
??private?String name;?
??public?ConcretePrototype01(String name) {?
????this.name = name;?
??}?
????
??public?void?getName() {?
????System.out.println(name);?
??}?
????
??//覆蓋Object基類中的clone()方法,并擴大該方法的訪問權限,具體化返回本類型?
??public?ConcretePrototype01 clone() {?
????ConcretePrototype01 self =?null;?
????try?{?
??????self = (ConcretePrototype01)?super.clone();?
????}?catch?(CloneNotSupportedException e) {?
??????e.printStackTrace();?
????}?
????return?self;?
??}?
}?
//測試類?
public?class?Client {?
??public?static?void?main(String[] args) {?
????ConcretePrototype01 prototype01 =?new?ConcretePrototype01("螞蟻 ...");?
????prototype01.getName();?
?????
????//通過clone獲得一個拷貝?
????ConcretePrototype01 fromClone01 = prototype01.clone();?
????fromClone01.getName();?
??}?
} 文章出處:http://haolloyin.blog.51cto.com/1177454/333442
轉載于:https://www.cnblogs.com/andyboy/p/3445205.html
總結
以上是生活随笔為你收集整理的(Prototype)原型模式的Java实现(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 乌鲁木齐昆仑域天赐学府是毛坯房还是精装修
- 下一篇: 乌鲁木齐中建玖悦是毛坯房还是精装修?