Java設計模式之原型模式

來源:互聯網
上載者:User

標籤:

原型模式簡介

原型模式實際上不算一種設計模式,應該說是一種技巧吧。當我們需要建立與已有對象一樣的對象時,我們通常可以有兩種容易想到的方法,一種是將已有對象指向另外一個重新建立的對象,如

//將old賦給newObject newObject=oldObject;



這種做法是相當於newObject還是指向oldObject的地址,也就是說,二者實際上是一樣的,未來也是一樣的,隨便對哪個對象變更,二者都會保持一致,因為可以把它們看做兩個相同的“指標”;另外一種常見的做法是,重新建立一個對象,用new來執行個體化,這樣就建立了另外一個對象,即向記憶體中再寫入了一個對象,雖然內容一樣,但地址不一樣,但是這種做法費力,如果對象比較複雜的話。

原型模式在這種需求下就誕生了,我們知道Object乃一切對象的父類(超類),並且Object有一個原生的clone方法,但是該方法的調用必須要求類實現了Cloneable介面,雖然Cloneable介面只是一個擺設,裡面空空蕩蕩,姑且就當Cloneable介面是clone方法實現的一個標誌吧!我們可以建立一個類實現Cloneable即可,在覆寫clone方法即可完成該類的複製了。

原型模式的代碼實現

下面寫一個Dog類,該類實現了Cloneable介面,並且覆寫了超類的clone方法,裡面使用了super.clone,表示調用超類的原生代碼即可。注意,Dog類有一個非基礎資料型別 (Elementary Data Type)的變數eye,下面會介紹這個點。

淺複製
package com.prototype;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Dog implements Cloneable,Serializable {/** *  */private static final long serialVersionUID = -2050795770781171788L;private String name;Eye eye;public Dog(Eye eye) {this.eye=eye;}public String getName() {return name;}public void setName(String name) {this.name=name;}@Overrideprotected Object clone() throws CloneNotSupportedException {Dog dog;dog=(Dog) super.clone();return dog;}    }class Eye implements Serializable{/** *  */private static final long serialVersionUID = -2723012171722328322L;String name;public Eye(String name) {this.name=name;}}



原型模式中的複製方法

在上面的原型模式代碼中,我們覆寫了clone方法,下面我們來進行一個測試:

測試代碼一:

package com.prototype;/** * @author zzw922cn * */public class Test1 {public static void main(String[] args) throws CloneNotSupportedException {Dog dog = new Dog(new Eye("紅眼睛"));dog.setName("狗一");Dog object1 = (Dog) dog.clone();object1.eye.name="綠眼睛";object1.setName("狗二");System.out.println(dog.eye.name);System.out.println(object1.eye.name);System.out.println(dog.getName());System.out.println(object1.getName());System.out.println(object1.equals(dog));System.out.println(object1==dog);System.out.println(object1.getClass().equals(dog.getClass()));}}



在上面的代碼中可以看到,object1是dog的複製對象,當我們複製完成以後,再對object1進行調用相關設定,改變其Eye類型的變數以及String類型的變數,會發生什麼呢?dog是否會發生變化呢?並且object1與dog是否一樣呢(equals和==)?它們是否屬於同樣的類呢?最後一個問題是毋庸置疑的,肯定是同一個類。

運行結果

綠眼睛綠眼睛狗一狗二falsefalsetrue



從運行結果中可以看到,在object1修改了eye對象以後,dog的eye對象的name也自動由紅眼睛變為綠眼睛,但是object1修改了String類型的name對象後,dog卻保持原有的name對象。這二者有什麼聯絡或區別嗎?聯絡是String和Eye都是非基礎資料型別 (Elementary Data Type),Java的八大基礎資料型別 (Elementary Data Type)有char,byte,int,short,long,float,double,boolean。區別是既然同屬非基礎資料型別 (Elementary Data Type),但是一個跟隨複製對象變化而變化,另外一個卻保持不變,這是很奇怪的。因為它是String類型,String是一個例外。因此,總結一下clone方法,我們得知複製對象的基礎資料型別 (Elementary Data Type)欄位是原有對象欄位的複製,但是非基本類型(String除外)並沒有複製,而是對原有對象的非基本類型的一個引用罷了,這種情況正如博文一開始中的newObject與oldObject兩者的關係。而String類型則是一個例外,它是對原有對象的一個複製,並非指向原有的String對象的地址。

這種clone一般稱為淺複製,即並沒有完全複製!

測試代碼二

下面來進行一次深複製,即完全複製。我使用流的方式來進行深度複製,即完全拷貝。

深複製
package com.prototype;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Dog implements Cloneable,Serializable {/** *  */private static final long serialVersionUID = -2050795770781171788L;private String name;Eye eye;public Dog(Eye eye) {this.eye=eye;}public String getName() {return name;}public void setName(String name) {this.name=name;}@Overrideprotected Object clone() throws CloneNotSupportedException {Dog dog;dog=(Dog) super.clone();return dog;}/* 深複製 */      public Object deepClone() throws IOException, ClassNotFoundException {            /* 寫入當前對象的二進位流 */          ByteArrayOutputStream bos = new ByteArrayOutputStream();          ObjectOutputStream oos = new ObjectOutputStream(bos);          oos.writeObject(this);            /* 讀出二進位流產生的新對象 */          ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());          ObjectInputStream ois = new ObjectInputStream(bis);          return ois.readObject();      }     }class Eye implements Serializable{/** *  */private static final long serialVersionUID = -2723012171722328322L;String name;public Eye(String name) {this.name=name;}}



接著寫一個類似的測試代碼

package com.prototype;import java.io.IOException;public class Test2 {/** * equal強調內容是否相同 * =強調地址是否相同 * @param args * @throws CloneNotSupportedException * @throws IOException  * @throws ClassNotFoundException  */public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {Dog dog = new Dog(new Eye("紅眼睛"));dog.setName("狗一");System.out.println("-----------------深複製--------------");Dog object2 = (Dog) dog.deepClone();object2.eye.name="綠眼睛";object2.setName("狗二");System.out.println(dog.eye.name);System.out.println(object2.eye.name);System.out.println(dog.getName());System.out.println(object2.getName());System.out.println(object2.equals(dog));System.out.println(object2==dog);System.out.println(object2.getClass().equals(dog.getClass()));}}



運行測試結果:
-----------------深複製--------------紅眼睛綠眼睛狗一狗二falsefalsetrue



我們看到深度複製,二者便“分道揚鑣”了,除了複製之初兩者是一樣的之外,後續的任何變化都不會對彼此產生任何影響了。這就是深複製。 equals與==的區別

前面我們看到複製對象與原始對象的equals和==都返回false,無論是淺複製還是深複製。那麼equals和==到底是什麼關係呢?

對於基礎資料型別 (Elementary Data Type),==比較的是它們的值。而對於非基本類型的對象,==比較是它們在記憶體中的地址,如之前的oldObject與newObject二者的地址相同;而equals方法,如果它沒有被子類覆寫,它最原始的也是比較對象在記憶體中的地址,如果被子類覆寫了,就不好說了。例如在String類型中,equals方法比較的是字串的“表面值”,它並不是比較對象在記憶體中的地址,而==比較的是兩個字串在記憶體中的地址是否一樣。例如String str1="Java",String str2=new String("Java");那麼二者的關係是str1!=str2,str1.equals(str2)=true。原因是str1存在於字串常量池中,str2存在於Java堆中,二者地址當然不同;但是二者的表面值是一樣的,都是Java,因此equals方法返回true。

Java設計模式之原型模式

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.