flash做網(wǎng)站網(wǎng)站查詢?nèi)肟?/h1>
文章目錄
- 概述
- 類圖
- 原型模式優(yōu)缺點
- 優(yōu)點
- 缺點
- 代碼實現(xiàn)

概述
在有些系統(tǒng)中,往往會存在大量相同或者是相似的對象,比如一個圍棋或者象棋程序中的旗子,這些旗子外形都差不多,只是演示或者是上面刻的內(nèi)容不一樣,若此時使用傳統(tǒng)的構造函數(shù)創(chuàng)建對象,那么簡單的對象還好,遇到稍微復雜一點的對象就會耗時耗資源,而使用原型設計模式會讓對象的生成高效很多
類圖
在本文中使用了人和身體的例子來演示原型模式,假如咱要造一個人的對象,需要設置人的屬性,姓名,年齡等,然后給他設置身體,大腦等器官,本例只是為了展示原型模式,只簡單的做了Person和Body的結合。
原型模式主要有三個角色
1.抽象原型類:它定義了具體的原型對象必須實現(xiàn)的接口。如本例子中的IProtoType接口
2.具體原型類: 實現(xiàn)抽象原型接口中的復制對象的方法,比如本例中的實現(xiàn)了原型接口中的 clone(),deepClone()方法的Person類
3.訪問類: 使用具體原型類中的復制對象方法生成新的對象,比如本例中中的Client
結合本文中的例子,原型設計模式的類圖如下所示:
原型模式優(yōu)缺點
優(yōu)點
原型設計模式的優(yōu)點主要有兩點,如下所示:
(1)可以優(yōu)化性能:在JAVA語言中,可以通過實現(xiàn)Cloneable接口,重寫clone方法來達到復制對象的目的,這種方式是基于內(nèi)存二進制流的復制,在性能上比直接使用new關鍵字創(chuàng)建一個對象高很多。
(2)可以使用原型模式中的深克隆方式保存對象的狀態(tài):我們可以使用原型模式將對象復制一份,并將其狀態(tài)保存起來。簡化了創(chuàng)建對象的過程,在需要的時候直接使用我們保存的對象,例如遇到需要恢復到歷史某一狀態(tài)的需求時,或者是需要實現(xiàn)撤銷操作的需求時,都可以考慮原型模式
缺點
當然,萬事萬物有優(yōu)點就會有缺點,原型模式的缺點主要有三個,如下所示:
(1)需要為每個類都配置一個克隆方法
(2)clone方法位于類的內(nèi)部,當對已有的類進行修改的時候,需要修改對應的實現(xiàn)代碼。不符合開閉原則(對修改關閉,對擴展開放)
(3)當實現(xiàn)深克隆時,需要編寫較為復雜的代碼,而且當對象之間存在多層嵌套引用時,每一層對象對應的類都必須支持深克隆,實現(xiàn)起來比較麻煩
深克隆:不僅拷貝對象的本身,而且拷貝對象包含的引用指向的所有對象
淺克隆:僅拷貝對象的本身,而不拷貝對象包含的引用指向的對象
使用一個例子解釋深克隆和淺克隆
public class Person {private static final Long VERSION = 1000L;private String name;private int age;private Body body;
// 省略構造函數(shù)以及get,set方法
}
比如我們要拷貝上面的Person對象,如果使用深克隆的方式拷貝,這時候Person對象中包含的Body對象也會被拷貝,也就是說,深克隆拷貝出的對象和原來的對象是完全獨立的,我們修改新克隆出的對象,不會影響原來的Person對象。假如使用淺克隆,這時只會拷貝Person中包含的Body對象的引用,也就是說使用淺克隆拷貝出來的新對象中包含的Body對象和原來的對象中包含的一樣,因為淺克隆將Body的引用拷貝給了新克隆出的對象,這時候如果修改新克隆出的對象,那么原來的Person對象的Body也會跟著變,后面會有例子證實這點
代碼實現(xiàn)
本文中,我們使用人和身體的例子來演示原型設計模式。首先我們定義出原型模式的接口,如下所示:
public interface IPrototype extends Cloneable{Person deepClone() throws IOException, ClassNotFoundException;
}
原型模式的接口繼承自Java的Cloneable接口,其中包含了一個clone()方法,用于實現(xiàn)淺克隆,而我們定義的接口中
包含了一個deepClone()方法,用于實現(xiàn)深克隆。
然后就是定義一個類實現(xiàn)原型設計模式的接口:
public class Person implements IPrototype, Serializable {private static final Long VERSION = 1000L;private String name;private int age;private Body body;public Person(String name, int age) {this.name = name;this.age = age;}public void setBody(Body body) {this.body = body;}public Body getBody() {return body;}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;}@Overridepublic Person clone() {try {return (Person) super.clone();} catch (CloneNotSupportedException e) {throw new AssertionError();}}public Person deepClone() throws IOException, ClassNotFoundException {// 將對象寫入到流中ByteArrayOutputStream byteArrayOutputStream =new ByteArrayOutputStream();ObjectOutputStream outputStream =new ObjectOutputStream(byteArrayOutputStream);outputStream.writeObject(this);// 將對象從流中取出ByteArrayInputStream byteArrayInputStream =new ByteArrayInputStream(byteArrayOutputStream.toByteArray());ObjectInputStream inputStream =new ObjectInputStream(byteArrayInputStream);return (Person) inputStream.readObject();}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", body=" + body +'}';}
}
需要注意的是,為了實現(xiàn)深克隆,我們需要借助Java的Serializable 接口標識本類可以被序列化。Person類中包含了基本類型的成員變量以及引用類型的成員變量Body,Body的定義如下:
public class Body implements Serializable {private static final Long VERSION = 1001L;private String sex;private String hand;public Body(String sex, String hand) {this.sex = sex;this.hand = hand;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getHand() {return hand;}public void setHand(String hand) {this.hand = hand;}@Overridepublic String toString() {return "Body{" +"sex='" + sex + '\'' +", hand='" + hand + '\'' +'}';}
}
為了能實現(xiàn)序列化,Body類也要實現(xiàn)Serializable接口。當需要使用淺克隆的時候,我們就通過Person對象的clone()方法來生成,,當需要使用深克隆的時候,我們就使用deepClone()方法來生成。
最后就是使用對應的克隆方法生成克隆對象
public class Client {public static void main(String[] args) throws IOException, ClassNotFoundException {// 創(chuàng)建一個Person對象Person person = new Person("walt", 18);// 創(chuàng)建出Body對象Body body = new Body("男", "男生的手");person.setBody(body);System.out.println("原始的Person: " + person);// 使用淺克隆生成一個克隆對象Person clonePerson = person.clone();System.out.println("克隆的Person: " + clonePerson);// 獲取到克隆對象的Body并做修改Body cloneBody = clonePerson.getBody();cloneBody.setSex("女");cloneBody.setHand("女生的手");clonePerson.setBody(cloneBody);// 分別打印出克隆的對象和原始對象System.out.println("克隆Person: " + clonePerson + " ,原始Person: " + person);// 檢查克隆對象的body和原始對象的body是否是同一個,是就為淺克隆,不是為深克隆System.out.println("克隆的Body是否等于原始的Body: " + (body == cloneBody));// 使用深克隆生成一個對象Person deepClonePerson = person.deepClone();// 獲取到深克隆后的person對象的body并修改Body deepCloneBody = deepClonePerson.getBody();deepCloneBody.setSex("深克隆男孩子");deepCloneBody.setHand("深克隆男生的手手");deepClonePerson.setBody(deepCloneBody);// 打印出深克隆后的對象和原始的對象System.out.println("深克隆Person: " + deepClonePerson + " ,原始Person: " + person);// 檢查克隆對象的body和原始對象的body是否是同一個,是就為淺克隆,不是為深克隆System.out.println("深克隆的Body是否等于原始的Body: " + (body == deepCloneBody));}
}
運行結果: