標籤:size 介面 基礎資料型別 (Elementary Data Type) 類型 iss support 原型模式 extend 支援
一、概述:
使用原型執行個體指定建立對象的種類,而且通過拷貝這些原型建立新的對象。
簡單的說就是對象的拷貝產生新的對象(對象的複製),原型模式是一種對象建立型模式。
二、使用情境:
建立新的對象能夠通過對已有對象進行複製來獲得,假設是相似對象,則僅僅需對其成員變數稍作改動。
三、UML結構圖:
四、參與者
(1) Prototype(抽象原型類):它是聲明複製方法的介面,是全部詳細原型類的公用父類,能夠是抽象類別也能夠是介面,甚至還能夠是詳細實作類別。
(2) ConcretePrototype(詳細原型類):它實如今抽象原型類中聲明的複製方法。在複製方法中返回自己的一個複製對象。
(3) Client(客戶類):讓一個原型對象複製自身從而建立一個全新的對象。
五、用例學習:
1、抽象原型類:Prototype.java
/** * 抽象原型類 * @author [email protected] * */public abstract class Prototype {/** * 提供抽象複製方法 */public abstract Prototype clone();}2、詳細原型類:ConcretePrototypeA.java
/** * 詳細原型類A * @author [email protected] * */public class ConcretePrototypeA extends Prototype {/** * 淺複製 */@Overridepublic Prototype clone() {Prototype prototype = new ConcretePrototypeA();return prototype;}}3、client測試類:Client.java
public class Client {public static void main(String[] args) {Prototype prototypeA = new ConcretePrototypeA();Prototype prototypeB = prototypeA.clone();System.out.println(prototypeB.equals(prototypeA)); // return falseSystem.out.println(prototypeB == prototypeA); // return falseSystem.out.println(prototypeB.getClass() == prototypeA.getClass()); // return true}}這裡我們能夠看到 prototypeA對象複製了一個對象prototypeB,可是prototypeA != prototypeB, 說明prototypeB是一個全新的Prototype對象。
注意:原型模式通過複製方法所建立的對象是全新的對象,它們在記憶體中擁有新的地址,通常對複製所產生的對象進行改動對原型對象不會造成不論什麼影響。每個複製對象都是相互獨立的。
六、擴充:
關於淺複製與深複製的簡介:
(1) 在Java語言中。資料類型分為實值型別(基礎資料型別 (Elementary Data Type))和參考型別。實值型別包含int、double、byte、boolean、char等單一資料型別。參考型別包含類、介面、數組等複雜類型。
例如以下Person對象:
public class Person {// 姓名private String name;// 年齡private int age;// 他的父親private Father father;}
name、age 為基礎資料型別 (Elementary Data Type),father就為參考型別。
淺複製和深複製的主要差別在於是否支援參考型別的成員變數的複製
(2)淺複製:
在Java語言中。通過覆蓋Object類的clone()方法就是實現淺複製,在淺複製中,當對象被複製時僅僅複製它本身和當中包括的實值型別的成員變數。而參考型別的成員對象並沒有複製。也就是說原型對象僅僅是將引用對象的地址複製一份給複製對象,複製對象和原型對象的參考型別成員變數還是指向同樣的記憶體位址。
注意:可以實現複製的Java類必須實現一個標識介面Cloneable,表示這個Java類支援被複製。假設一個類沒有實現這個介面可是調用了clone()方法。Java編譯器將拋出一個CloneNotSupportedException異常。
用代碼說話:
1、引用對象:Father.java
public class Father{// 姓名private String name;// 年齡private int age;public Father(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}2、複製原型類: Person.java
public class Person implements Cloneable{// 姓名private String name;// 年齡private int age;// 他的父親private Father father;/** * 重寫 Object對象的clone方法實現Person對象的複製 */public Person clone(){Object obj = null;try {obj = super.clone();return (Person)obj;} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Father getFather() {return father;}public void setFather(Father father) {this.father = father;}}3、測試類:CloneClient.java
public class CloneClient {public static void main(String[] args) {Father father = new Father("老子", 50);Person son = new Person();son.setName("兒子");son.setAge(24);son.setFather(father);// 淺複製出一個兄弟Person對象Person brother = son.clone();System.out.println(brother == son); // return falseSystem.out.println(brother.getFather() == son.getFather()); // return true}}以上 我們能夠分析看到son 淺複製出一個"兄弟"對象 brother,可是他們的引用對象"父親"都是同一個對象,全部事實證明淺複製沒有對參考型別對象進行複製。
(3)深複製:
在深複製中。不管原型對象的成員變數是實值型別還是參考型別,都將複製一份給複製對象,簡單來說,在深複製中。除了對象本身被複製外,對象所包括的全部成員變數也將複製。
那麼怎樣實現深複製呢?
在Java語言中。假設須要實現深複製。能夠通過序列化(Serialization)等方式來實現。序列化就是將對象寫到流的過程。寫到流中的對象是原有對象的一個拷貝,而原對象仍然存在於記憶體中。
通過序列化實現的拷貝不僅能夠複製對象本身,並且能夠複製其引用的成員對象,因此通過序列化將對象寫到一個流中,再從流裡將其讀出來。能夠實現深複製。須要注意的是能夠實現序列化的對象其類必須實現Serializable介面。否則無法實現序列化操作。
用代碼說話:
1、引用類:Father.java
import java.io.Serializable;public class Father implements Serializable{// 姓名private String name;// 年齡private int age;public Father(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}2、複製原型類: Person.java
import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.OptionalDataException;import java.io.Serializable;public class Person implements Serializable{// 姓名private String name;// 年齡private int age;// 他的父親private Father father;/** * 深複製 * @return * @throws IOException * @throws ClassNotFoundException * @throws OptionalDataException */public Person deepClone() throws IOException, ClassNotFoundException, OptionalDataException{ //將對象寫入流中 ByteArrayOutputStream bao=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bao); oos.writeObject(this); //將對象從流中取出 ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray()); ObjectInputStream ois=new ObjectInputStream(bis); return (Person) ois.readObject();}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Father getFather() {return father;}public void setFather(Father father) {this.father = father;}}3、深複製測試類:DeepCloneClient.java
public class DeepCloneClient {public static void main(String[] args) {Father father = new Father("老子", 50);Person son = new Person();son.setName("兒子");son.setAge(24);son.setFather(father);try {Person brother = son.deepClone();System.out.println(brother == son); // falseSystem.out.println(brother.getFather() == son.getFather()); // false} catch (OptionalDataException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}以上我們能夠分析看到通過深複製出來的"兄弟"對象brother 和 son 不僅不等、就連他們的參考型別Father也不等啦。
全部證明:通過深複製 複製出了一個全然獨立的全新的對象。
JAVA設計模式之 原型模式【Prototype Pattern】