GOF23设计模式(创建型模式) 原型模式
目錄
一:原型模式的定義
二:關于深克隆和深克隆的區別
三:反序列化的方式實現深克隆
原型模式:
通過new產生一個對象需要非常繁瑣的數據準備或訪冋權限,則可以使用原型模式。
就是java中的克隆技術,以某個對象為原型,復制出新的對象。顯然,新的對象具備原型對象的特點
優勢有:效率高(直接克隆,避免了重新執行構造過程步驟).
克隆類似于new,但是不同于new。new創建新的對象屬性采用的是默認值。克隆出的對象的屬性值完全和原型對象相同。并且克隆出的新對象改變不會影晌原型對象。然后,再修改克隆對象的值
原型模式實現:
繼承Cloneable接囗和重寫clone()方法
詳解深克隆與淺克隆的區別示例:
打個比方,比如我們我們考試的時候,要抄別人的試卷,根據原型模式的思想,是沒有必要從頭到尾抄一遍的,而是把別人的試卷克隆一份,在這基礎上進行修改就行了,而java給我們提供了clone()方法,讓我們看看jdk里面的描述:
| public interface Cloneable 一個類實現Cloneable接口,以指示Object.clone()方法,該方法對于該類的實例進行現場復制是合法的。 在不實現Cloneable接口的實例上調用對象的克隆方法導致拋出異常CloneNotSupportedException 。 按照慣例,實現此接口的類應使用公共方法覆蓋Object.clone (受保護)。 |
因此,我們要用clone()方法,必須繼承Cloneable接口!!!!!!!!
關于克隆,其實分別兩類:
| 復制對象時僅僅復制對象本身,包括基本數據類型的屬性,但該對象的屬性為引用數據類型時,不會進行復制引用的對象,即拷貝出來的對象與被拷貝出來的對象中的屬性引用的對象是同一個。 |
| 創建一個新對象,屬性中引用的其他對象也會被克隆,不再指向原有對象地址。 |
?
接下來,我將以試卷的克隆為例,實現一下clone()方法,并分析一下淺克隆和深克隆的區別~
- 首先創建一個試卷類test_paper繼承Cloneable接口,然后我們就實現Object類的clone()方法,該類有兩個私有屬性,一個是姓名name(基本數據類型)、一個是日期date(引用數據類型),添加對應的構造器和set、get方法
package 四_原型模式;import java.util.Date;/*** 克隆試卷*/public class test_paper implements Cloneable {String name;//名字,基本數據類型Date date;//日期,引用數據類型//克隆方法@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}public test_paper() {}public test_paper(String name, Date date) {this.name = name;this.date = date;}public String getName() {return name;}@Overridepublic String toString() {return "test_paper{" +"name='" + name + '\'' +", date=" + date +'}';}public void setName(String name) {this.name = name;}public Date getDate() {return date;}public void setDate(Date date) {this.date = date;}} ?
? ? ? ? ? 2. 然后我們在主函數里面進行測試
package 四_原型模式;import java.util.Date;@SuppressWarnings("all")public class Client {public static void main(String[] args) throws CloneNotSupportedException {Date date = new Date();String name = "zsr";test_paper paper1 = new test_paper(name, date);test_paper paper2 = (test_paper) paper1.clone();//通過paper1克隆出的對象paper2.getDate().setDate(1000);paper2.setName("gcc");//如果修改paper2的引用類型(非基本數據類型)屬性值,//paper1的對應的引用類型屬性值會跟著更改,因為這是淺克隆,克隆出的對象和元對象指向同一個屬性System.out.println(paper1);System.out.println(paper2);}} ?
根據運行結果,我們發現正確克隆出了一張新的試卷,
- 我們修改克隆出的試卷的基本類型的屬性name,原試卷對應的name屬性并沒有改變
- 但是我們修改克隆對象試卷的引用類型屬性date,原試卷的date屬性值跟著改變了,這就是淺復制
- 淺復制復制的時候復制了自己的本身,以及本身的基本類型的屬性,但是對于自己的非基本數據類型的屬性,并沒有復制出一個新的相應的引用對象,即復制出來的對象與原對象中的非基本類型屬性引用的對象是同一個!!所以對引用類型的屬性進行修改,原對象和克隆對象對應的屬性值都會改變!!!!!!
這樣就沒有達到完全復制、原對象和克隆對象相互之間完全沒有影響的目的。那如果我們都想復制呢??那就引入了深復制~~
我們只需要在clone()方法中添加對應非基本類型屬性的復制
在這個示例中,即加入對date屬性的復制即可~
??? //克隆方法@Overrideprotected Object clone() throws CloneNotSupportedException {test_paper paper = (test_paper) super.clone();paper.date = (Date) date.clone();return paper;} ?
根據我們新的實驗結果,我們發現,修改paper2的所有屬性值,對應的paper1元對象的屬性值都不會改變,這就是深克隆,達到了元對象和克隆對象之間不會影響的效果!!
當然,實現深復制的方式可不止這么一種,我們還可以通過實現序列化和反序列化的方式實現深復制~
代碼實現:
package 四_原型模式;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.util.Date;@SuppressWarnings("all")public class Client {public static void main(String[] args) throws Exception {Date date = new Date();String name = "zsr";test_paper paper1 = new test_paper(name, date);//通過序列化和反序列化來實現深克隆ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream obs = new ObjectOutputStream(bos);obs.writeObject(paper1);byte a[] = bos.toByteArray();ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(a));test_paper paper3 = (test_paper) ois.readObject();//獲取到新對象paper3.getDate().setDate(1000);//改變非基本類型屬性System.out.println(paper1);System.out.println(paper3);}} ?
根據實驗結果,我們成功利用序列化和反序列化實現了深克隆~
總結
以上是生活随笔為你收集整理的GOF23设计模式(创建型模式) 原型模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GOF23设计模式(创建型模式)建造者模
- 下一篇: hexo框架个人博客的搭建(面试加分!)