日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
設(shè)計(jì)模式系列—原型模式

前言

創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供峨邊彝族網(wǎng)站建設(shè)、峨邊彝族做網(wǎng)站、峨邊彝族網(wǎng)站設(shè)計(jì)、峨邊彝族網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、峨邊彝族企業(yè)網(wǎng)站模板建站服務(wù),十載峨邊彝族做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

  • 23種設(shè)計(jì)模式速記
  • 單例(singleton)模式
  • 工廠方法(factory method)模式
  • 抽象工廠(abstract factory)模式
  • 建造者/構(gòu)建器(builder)模式

23種設(shè)計(jì)模式快速記憶的請看上面第一篇,本篇和大家一起來學(xué)習(xí)原型模式,在學(xué)習(xí)原型模式之前我們需要先認(rèn)識(shí)下淺拷貝和深拷貝這兩個(gè)概念。

淺拷貝和深拷貝
淺拷貝
淺拷貝是按位拷貝對象,它會(huì)創(chuàng)建一個(gè)新對象,這個(gè)對象有著原始對象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內(nèi)存地址(引用類型),拷貝的就是內(nèi)存地址 ,因此如果其中一個(gè)對象改變了這個(gè)地址,就會(huì)影響到另一個(gè)對象。

復(fù)制了對象的引用地址,兩個(gè)對象指向同一個(gè)內(nèi)存地址,所以修改其中任意的值,另一個(gè)值都會(huì)隨之變化。

深拷貝
深拷貝會(huì)拷貝所有的屬性,并拷貝屬性指向的動(dòng)態(tài)分配的內(nèi)存。當(dāng)對象和它所引用的對象一起拷貝時(shí)即發(fā)生深拷貝。深拷貝相比于淺拷貝速度較慢并且花銷較大。

將對象及值復(fù)制過來,兩個(gè)對象修改其中任意的值另一個(gè)值不會(huì)改變。

模式定義
用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。

原型模式其實(shí)就是一個(gè)對象在創(chuàng)建另一個(gè)可定制的對象,而且不需要指定任何創(chuàng)建的細(xì)節(jié)。Java提供了Coneable接口,其中有一個(gè)唯一方法Clone(),實(shí)現(xiàn)這個(gè)接口就可以完成原型模式了。

實(shí)例說明
淺拷貝案例
聲明 User 實(shí)體類,需要實(shí)現(xiàn) Cloneable 接口,并覆寫 clone() 方法。

User 屬性包括基礎(chǔ)數(shù)據(jù)類型和引用數(shù)據(jù)類型,方便演示

 
 
 
 
  1. package com.niuh.designpattern.prototype; 
  2.  
  3. /** 
  4.  * 用戶信息 
  5.  */ 
  6. public class User implements Cloneable { 
  7.  
  8.     // 基礎(chǔ)數(shù)據(jù)類型 
  9.     private int id; 
  10.     private String name; 
  11.     private String sex; 
  12.     private String pwd; 
  13.  
  14.     // 引用數(shù)據(jù)類型 
  15.     private BaseInfo baseInfo; 
  16.  
  17.     public User(int id, String name, String sex, String pwd, BaseInfo baseInfo) { 
  18.         this.id = id; 
  19.         this.name = name; 
  20.         this.sex = sex; 
  21.         this.pwd = pwd; 
  22.         this.baseInfo = baseInfo; 
  23.     } 
  24.  
  25.     public int getId() { 
  26.         return id; 
  27.     } 
  28.  
  29.     public void setId(int id) { 
  30.         this.id = id; 
  31.     } 
  32.  
  33.     public String getName() { 
  34.         return name; 
  35.     } 
  36.  
  37.     public void setName(String name) { 
  38.         this.name = name; 
  39.     } 
  40.  
  41.     public String getSex() { 
  42.         return sex; 
  43.     } 
  44.  
  45.     public void setSex(String sex) { 
  46.         this.sex = sex; 
  47.     } 
  48.  
  49.     public String getPwd() { 
  50.         return pwd; 
  51.     } 
  52.  
  53.     public void setPwd(String pwd) { 
  54.         this.pwd = pwd; 
  55.     } 
  56.  
  57.     public BaseInfo getBaseInfo() { 
  58.         return baseInfo; 
  59.     } 
  60.  
  61.     public void setBaseInfo(BaseInfo baseInfo) { 
  62.         this.baseInfo = baseInfo; 
  63.     } 
  64.  
  65.     @Override 
  66.     public String toString() { 
  67.         return "hashCode: " + super.hashCode() + ", User{" + 
  68.                 "id=" + id + 
  69.                 ", name='" + name + '\'' + 
  70.                 ", sex='" + sex + '\'' + 
  71.                 ", pwd='" + pwd + '\'' + 
  72.                 ", baseInfo=" + baseInfo + 
  73.                 '}'; 
  74.     } 
  75.  
  76.     @Override 
  77.     protected User clone() throws CloneNotSupportedException { 
  78.         return (User) super.clone(); 
  79.     } 

 
 
 
 
  1. package com.niuh.designpattern.prototype; 
  2.  
  3. import java.util.Date; 
  4.  
  5. /** 
  6.  * 基礎(chǔ)類 
  7.  */ 
  8. public class BaseInfo { 
  9.  
  10.     private String desc; 
  11.  
  12.     // ....... 
  13.  
  14.  
  15.     public BaseInfo(String desc) { 
  16.         this.desc = desc; 
  17.     } 
  18.  
  19.     public String getDesc() { 
  20.         return desc; 
  21.     } 
  22.  
  23.     public void setDesc(String desc) { 
  24.         this.desc = desc; 
  25.     } 
  26.  
  27.     @Override 
  28.     public String toString() { 
  29.         return "BaseInfo{" + 
  30.                 "desc=" + desc + 
  31.                 '}'; 
  32.     } 

 
 
 
 
  1. package com.niuh.designpattern.prototype; 
  2.  
  3.  
  4. /** 
  5.  * 原型設(shè)計(jì)模式 
  6.  */ 
  7. public class PrototypePattern { 
  8.     public static void main(String[] args) throws CloneNotSupportedException { 
  9.  
  10.         BaseInfo baseInfo = new BaseInfo("張三"); 
  11.  
  12.         User user1 = new User(1, "張三", "男", "123456", baseInfo); 
  13.  
  14.         // new User  ...... 
  15.  
  16.         // 克隆機(jī)制 
  17.         User user2 = user1.clone(); 
  18.         user2.setId(2); 
  19.         user2.setName("李四"); 
  20.         BaseInfo baseInfo1 = user2.getBaseInfo(); 
  21.         baseInfo1.setDesc("李四"); 
  22.  
  23.  
  24.         System.out.println(user1); 
  25.         System.out.println(user2); 
  26.  
  27.     } 

輸出結(jié)果如下:

由輸出的結(jié)果可見,通過 user1.clone() 拷貝對象后得到的 user2,和 user1 是兩個(gè)不同的對象,HashCode 值不一樣。user1 和 user2 的基礎(chǔ)數(shù)據(jù)類型的修改互不影響,而引用類型 baseInfo 修改后是會(huì)有影響的。

深拷貝案例
通過上面的例子可以看到,淺拷貝會(huì)帶來數(shù)據(jù)安全方面的隱患,例如我們只是想修改了 user2 的 baseInfo,但是 user1 的 baseInfo 也被修改了,因?yàn)樗鼈兌际侵赶虻耐粋€(gè)地址。所以,此種情況下,我們需要用到深拷貝。

深拷貝,在拷貝引用類型成員變量時(shí),為引用類型的數(shù)據(jù)成員另辟了一個(gè)獨(dú)立的內(nèi)存空間,實(shí)現(xiàn)真正內(nèi)容上的拷貝。

對于 User 的引用類型的成員變量 BaseInfo ,需要實(shí)現(xiàn) Cloneable 并重寫 clone() 方法。

 
 
 
 
  1. package com.niuh.designpattern.prototype; 
  2.  
  3. import java.util.Date; 
  4.  
  5. /** 
  6.  * 基礎(chǔ)類 
  7.  */ 
  8. public class BaseInfo implements Cloneable { 
  9.  
  10.     private String desc; 
  11.  
  12.     // ....... 
  13.  
  14.  
  15.     public BaseInfo(String desc) { 
  16.         this.desc = desc; 
  17.     } 
  18.  
  19.     public String getDesc() { 
  20.         return desc; 
  21.     } 
  22.  
  23.     public void setDesc(String desc) { 
  24.         this.desc = desc; 
  25.     } 
  26.  
  27.     @Override 
  28.     public String toString() { 
  29.         return "BaseInfo{" + 
  30.                 "desc=" + desc + 
  31.                 '}'; 
  32.     } 
  33.  
  34.     @Override 
  35.     protected BaseInfo clone() throws CloneNotSupportedException { 
  36.         //BaseInfo 如果也有引用類型的成員屬性,也應(yīng)該和 User 類一樣實(shí)現(xiàn) 
  37.         return (BaseInfo) super.clone(); 
  38.     } 

在 User 的 clone() 方法中,需要拿到拷貝自己后產(chǎn)生的新的對象,然后對新的對象的引用類型再調(diào)用拷貝操作,實(shí)現(xiàn)對引用類型成員變量的深拷貝。

 
 
 
 
  1. package com.niuh.designpattern.prototype; 
  2.  
  3. /** 
  4.  * 用戶信息 
  5.  */ 
  6. public class User implements Cloneable { 
  7.  
  8.     // 基礎(chǔ)數(shù)據(jù)類型 
  9.     private int id; 
  10.     private String name; 
  11.     private String sex; 
  12.     private String pwd; 
  13.  
  14.     // 引用數(shù)據(jù)類型 
  15.     private BaseInfo baseInfo; 
  16.  
  17.     public User(int id, String name, String sex, String pwd, BaseInfo baseInfo) { 
  18.         this.id = id; 
  19.         this.name = name; 
  20.         this.sex = sex; 
  21.         this.pwd = pwd; 
  22.         this.baseInfo = baseInfo; 
  23.     } 
  24.  
  25.     public int getId() { 
  26.         return id; 
  27.     } 
  28.  
  29.     public void setId(int id) { 
  30.         this.id = id; 
  31.     } 
  32.  
  33.     public String getName() { 
  34.         return name; 
  35.     } 
  36.  
  37.     public void setName(String name) { 
  38.         this.name = name; 
  39.     } 
  40.  
  41.     public String getSex() { 
  42.         return sex; 
  43.     } 
  44.  
  45.     public void setSex(String sex) { 
  46.         this.sex = sex; 
  47.     } 
  48.  
  49.     public String getPwd() { 
  50.         return pwd; 
  51.     } 
  52.  
  53.     public void setPwd(String pwd) { 
  54.         this.pwd = pwd; 
  55.     } 
  56.  
  57.     public BaseInfo getBaseInfo() { 
  58.         return baseInfo; 
  59.     } 
  60.  
  61.     public void setBaseInfo(BaseInfo baseInfo) { 
  62.         this.baseInfo = baseInfo; 
  63.     } 
  64.  
  65.     @Override 
  66.     public String toString() { 
  67.         return "hashCode: " + super.hashCode() + ", User{" + 
  68.                 "id=" + id + 
  69.                 ", name='" + name + '\'' + 
  70.                 ", sex='" + sex + '\'' + 
  71.                 ", pwd='" + pwd + '\'' + 
  72.                 ", baseInfo=" + baseInfo + 
  73.                 '}'; 
  74.     } 
  75.  
  76.     @Override 
  77.     protected User clone() throws CloneNotSupportedException { 
  78.         // 深拷貝 
  79.         User user = (User) super.clone(); 
  80.         user.baseInfo = baseInfo.clone(); 
  81.         return user; 
  82.     } 

與上面的使用方式一樣,輸出結(jié)果如下:

由輸出結(jié)果可見,深拷貝后,不管是基礎(chǔ)數(shù)據(jù)類型還是引用類型的成員變量,修改其值都不會(huì)相互造成影響。

序列化機(jī)制實(shí)現(xiàn)深拷貝
需要在 User 類實(shí)現(xiàn) Serializable,成員類型(BaseInfo)也需要實(shí)現(xiàn) Serializable 接口。

 
 
 
 
  1. package com.niuh.designpattern.prototype; 
  2.  
  3. import java.io.ByteArrayInputStream; 
  4. import java.io.ByteArrayOutputStream; 
  5. import java.io.IOException; 
  6. import java.io.ObjectInputStream; 
  7. import java.io.ObjectOutputStream; 
  8. import java.io.Serializable; 
  9.  
  10. /** 
  11.  * 用戶信息 
  12.  */ 
  13. public class User implements Cloneable , Serializable { 
  14.  
  15.     // 基礎(chǔ)數(shù)據(jù)類型 
  16.     private int id; 
  17.     private String name; 
  18.     private String sex; 
  19.     private String pwd; 
  20.  
  21.     // 引用數(shù)據(jù)類型 
  22.     private BaseInfo baseInfo; 
  23.  
  24.     public User(int id, String name, String sex, String pwd, BaseInfo baseInfo) { 
  25.         this.id = id; 
  26.         this.name = name; 
  27.         this.sex = sex; 
  28.         this.pwd = pwd; 
  29.         this.baseInfo = baseInfo; 
  30.     } 
  31.  
  32.     public int getId() { 
  33.         return id; 
  34.     } 
  35.  
  36.     public void setId(int id) { 
  37.         this.id = id; 
  38.     } 
  39.  
  40.     public String getName() { 
  41.         return name; 
  42.     } 
  43.  
  44.     public void setName(String name) { 
  45.         this.name = name; 
  46.     } 
  47.  
  48.     public String getSex() { 
  49.         return sex; 
  50.     } 
  51.  
  52.     public void setSex(String sex) { 
  53.         this.sex = sex; 
  54.     } 
  55.  
  56.     public String getPwd() { 
  57.         return pwd; 
  58.     } 
  59.  
  60.     public void setPwd(String pwd) { 
  61.         this.pwd = pwd; 
  62.     } 
  63.  
  64.     public BaseInfo getBaseInfo() { 
  65.         return baseInfo; 
  66.     } 
  67.  
  68.     public void setBaseInfo(BaseInfo baseInfo) { 
  69.         this.baseInfo = baseInfo; 
  70.     } 
  71.  
  72.     @Override 
  73.     public String toString() { 
  74.         return "hashCode: " + super.hashCode() + ", User{" + 
  75.                 "id=" + id + 
  76.                 ", name='" + name + '\'' + 
  77.                 ", sex='" + sex + '\'' + 
  78.                 ", pwd='" + pwd + '\'' + 
  79.                 ", baseInfo=" + baseInfo + 
  80.                 '}'; 
  81.     } 
  82.  
  83.     @Override 
  84.     protected User clone() throws CloneNotSupportedException { 
  85.         // 深拷貝 
  86.         // User user = (User) super.clone(); 
  87.         // user.baseInfo = baseInfo.clone(); 
  88.         // return user; 
  89.  
  90.  
  91.         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
  92.  
  93.         try (ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) { 
  94.  
  95.             oos.writeObject(this); 
  96.  
  97.         } catch (IOException e) { 
  98.             e.printStackTrace(); 
  99.         } 
  100.  
  101.         ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); 
  102.  
  103.         try (ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) { 
  104.             try { 
  105.                 User user = (User) ois.readObject(); 
  106.                 return user; 
  107.             } catch (ClassNotFoundException e) { 
  108.                 e.printStackTrace(); 
  109.             } 
  110.         } catch (IOException e) { 
  111.             e.printStackTrace(); 
  112.         } 
  113.         return null; 
  114.     } 

這個(gè)時(shí)候并沒有使用Java深拷貝,改變成員屬性Baseinfo,也能保存對象的獨(dú)立性。

通過序列化機(jī)制來完成深拷貝不推薦使用,因?yàn)樾蛄谢僮魇荂PU密集型,解析流是比較消耗性能,速度會(huì)比較慢

優(yōu)點(diǎn)

  • 可以不耦合具體類的情況下克隆對象
  • 避免重復(fù)的初始化代碼
  • 更方便的構(gòu)建復(fù)雜對象

缺點(diǎn)

  • 適用性不是很廣。
  • 每一個(gè)類必須配備一個(gè)克隆方法。
  • 配備克隆方法需要對類的功能進(jìn)行通盤考慮,這對于全新的類不是很難,但對于已有的類不一定很容易,特別當(dāng)一個(gè)類引用不支持串行化的間接對象,或者引用含有循環(huán)結(jié)構(gòu)的時(shí)候。

應(yīng)用場景
當(dāng)代碼不應(yīng)該依賴于需要復(fù)制的對象的具體類時(shí),請使用Prototype模式。

  • 某些結(jié)構(gòu)復(fù)雜的對象的創(chuàng)建工作;由于需求的變化,這些對象經(jīng)常面臨著劇烈的變化,但是他們卻擁有比較穩(wěn)定一致的接口;
  • 一般在初始化的信息不發(fā)生變化的情況下,克隆是最好的方法。

源碼中的應(yīng)用

 
 
 
 
  1. #Spring  
  2. org.springframework.beans.factory.support.AbstractBeanDefinition 
  3. #JDK 
  4. java.util.Arrays 
  5. java.util.ArrayList 
  6. ...... 

ArrayList中的使用
ArrayList也有clone()方法,如下

  • 返回一個(gè)Object對象,所以在使用此方法的時(shí)候要強(qiáng)制轉(zhuǎn)換。
  • ArrayList的本質(zhì)是維護(hù)了一個(gè)Object的數(shù)組,所以克隆也是通過數(shù)組的復(fù)制實(shí)現(xiàn)的,屬于淺復(fù)制。
 
 
 
 
  1. @Override  
  2.   public Object clone() { 
  3.     try { 
  4.         ArrayList result = (ArrayList) super.clone(); 
  5.         result.array = array.clone(); 
  6.         return result; 
  7.     } catch (CloneNotSupportedException e) { 
  8.        throw new AssertionError(); 
  9.     } 

ArrayList的Clone淺復(fù)制的巧妙使用
當(dāng)你需要使用remove方法移除掉集合中的對象,而非要修改集合中的對象的時(shí)候,可以選擇使用。

 
 
 
 
  1. //添加兩個(gè)元素 
  2. Student stJack=new Student("Jack", 13); 
  3. Student stTom=new Student("Tom", 15); 
  4. list.add(stJack); 
  5. list.add(stTom); 
  6.  
  7. //克隆 
  8. ArrayList listCopy=(ArrayList) list.clone(); 
  9.  
  10. //移除且不修改 
  11. listCopy.remove(1); 
  12. System.out.println(list); 
  13. System.out.println(listCopy); 

移除且不修改集合中的元素,只是在List內(nèi)部的數(shù)組中移除了指向元素的地址,可以放心的使用clone。

PS:以上代碼提交在 Github :https://github.com/Niuh-Study/niuh-designpatterns.git


本文標(biāo)題:設(shè)計(jì)模式系列—原型模式
分享鏈接:http://m.5511xx.com/article/cdpephe.html