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

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
五分鐘掌握原型模式

大家好,我是老田,今天我給大家分享設(shè)計(jì)模式中的原型模式。用貼切的生活故事,以及真實(shí)項(xiàng)目場(chǎng)景來(lái)講設(shè)計(jì)模式,最后用一句話來(lái)總結(jié)這個(gè)設(shè)計(jì)模式。

創(chuàng)新互聯(lián)公司提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì),成都品牌網(wǎng)站建設(shè),廣告投放平臺(tái)等致力于企業(yè)網(wǎng)站建設(shè)與公司網(wǎng)站制作,10余年的網(wǎng)站開(kāi)發(fā)和建站經(jīng)驗(yàn),助力企業(yè)信息化建設(shè),成功案例突破上千家,是您實(shí)現(xiàn)網(wǎng)站建設(shè)的好選擇.

故事

還記得大四那年找工作,無(wú)意中我得從網(wǎng)上找到一份相對(duì)漂亮的程序員簡(jiǎn)歷模板,然后全班同學(xué)開(kāi)啟瘋狂的簡(jiǎn)歷拷貝(U盤)。同時(shí)也鬧出了一個(gè)笑話,有幾位同學(xué),拷貝過(guò)去的簡(jiǎn)歷,內(nèi)容完全沒(méi)改,名字都沒(méi)有改,截止投給面試官(校招面試官)。后來(lái),結(jié)果大家也應(yīng)該能猜出來(lái),大家都去實(shí)習(xí)了,部分人還在找工作。后面公司面試官和同伴的其他同學(xué)反饋:收到一毛一樣的簡(jiǎn)歷,好幾份,回來(lái)大家一聊就知道問(wèn)題出哪里了,承認(rèn)了自己拷貝過(guò)去完全沒(méi)改就拿出去投了,害,尷尬的一匹。

把簡(jiǎn)歷拷貝分為為兩種:

  • 一種是拷貝簡(jiǎn)歷,然后把信息修改成自己的
  • 另外一種是,拷貝簡(jiǎn)歷,內(nèi)容什么都不改。

原型模式定義

Specify the kinds of objects to create using a prototype instance ,and create new objects by coping this prototype

大致意思:用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過(guò)復(fù)制這些原型創(chuàng)建新的對(duì)象。

原型模式:Prototype Pattern,屬于創(chuàng)建型模式。

調(diào)用者不需要知道任何創(chuàng)建細(xì)節(jié),也不用調(diào)用構(gòu)造方法來(lái)創(chuàng)建對(duì)象。

使用場(chǎng)景

原型模式有如下使用場(chǎng)景:

  • 類初始化消耗資源較多
  • new產(chǎn)生的一個(gè)對(duì)象需要非常繁瑣的過(guò)程(數(shù)據(jù)準(zhǔn)備、訪問(wèn)權(quán)限等)
  • 構(gòu)造函數(shù)比較復(fù)雜
  • 循環(huán)體內(nèi)生成大量對(duì)象時(shí)
  • 在Spring中,原型模式應(yīng)用的非常廣泛,例如:scope='prototype'

我們可以將一些getter和setter之類封裝成一個(gè)工廠方法,然后對(duì)于使用的人來(lái)說(shuō),調(diào)用方法就可以了,不需要知道里面的getter和setter是怎么處理的。我們也可以使用JDK提供的實(shí)現(xiàn)Cloneable接口,實(shí)現(xiàn)快速?gòu)?fù)制。

創(chuàng)建對(duì)象的四種方式:

new、反射、克隆、序列化

實(shí)際案例

大家是否有遇到過(guò)這種常見(jiàn),就是項(xiàng)目中規(guī)定,不能把與數(shù)據(jù)庫(kù)表映射的entity類返回給前端,所以通常返回給前端的有各種O,比如:XxxVO、XxxBO、XxxDTO...

這時(shí)候就會(huì)出現(xiàn)下面的場(chǎng)景,大家也想已經(jīng)猜到了。

下面是與數(shù)據(jù)庫(kù)表映射的UserEntity實(shí)體類。

 
 
 
 
  1. public class UserEntity {
  2.     private Long id;
  3.     private String name;
  4.     private Integer age;
  5.     //....可能還有很多屬性
  6.     //省略getter setter
  7. }

返回給前端或者調(diào)用方的UserVO實(shí)體類。

 
 
 
 
  1. public class UserVO {
  2.     private Long id;
  3.     private String name;
  4.     private Integer age;
  5.     //....可能還有很多屬性
  6.     //省略getter setter
  7. }

此時(shí),從數(shù)據(jù)庫(kù)里查出來(lái)的UserEntity需要轉(zhuǎn)換成UserVO,然后再返回給前端(或者調(diào)用方)。

 
 
 
 
  1. public class ObjectConvertUtil {
  2.     public static UserVo convertUserEntityToUserVO(UserEntity userEntity) {
  3.         if (userEntity == null) {
  4.             return null;
  5.         }
  6.         UserVo userVo = new UserVo();
  7.         userVo.setId(userEntity.getId());
  8.         userVo.setName(userEntity.getName());
  9.         userVo.setAge(userEntity.getAge());
  10.          //如果還有更多屬性呢?
  11.         return userVo;
  12.     }
  13. }

從這個(gè)util類中,我們可以看出,如果一個(gè)類的屬性有幾十個(gè),上百個(gè)的,這代碼量是不是有點(diǎn)恐怖?

于是,我們通常都會(huì)使用一些工具類來(lái)處理,比如常見(jiàn)有以下:

 
 
 
 
  1. BeanUtils.copy();
  2. JSON.parseObject()
  3. Guava工具類
  4. .....

這些工具類就用到了原型模式。

通過(guò)一個(gè)對(duì)象,創(chuàng)建一個(gè)新的對(duì)象。

也把原型模式稱之為對(duì)象的拷貝、克隆。

其實(shí)對(duì)象的克隆分淺克隆和深克隆,下面我們就來(lái)聊聊淺克隆和深克隆。

  • 淺克隆:創(chuàng)建一個(gè)新對(duì)象,新對(duì)象的屬性和原來(lái)對(duì)象完全相同,對(duì)于非基本類型屬性,仍指向原來(lái)對(duì)象的屬性所指向的對(duì)象的內(nèi)存地址。
  • 深克?。簞?chuàng)建一個(gè)新對(duì)象,屬性中引用的其他對(duì)象也會(huì)被克隆,不再指向原有對(duì)象地址。

我們先來(lái)聊聊淺克隆,都喜歡由淺入深。

淺克隆

比如,我現(xiàn)在相對(duì)用戶信息User進(jìn)行克隆,但是User中有用戶地址信息UserAddress屬性。

以下是代碼的實(shí)現(xiàn):

 
 
 
 
  1. //用戶地址信息
  2. public class UserAddress  implements Serializable{
  3.     private String province;
  4.     private String cityCode;
  5.     public UserAddress(String province, String cityCode) {
  6.         this.province = province;
  7.         this.cityCode = cityCode;
  8.     }
  9. }
  10. //用戶信息
  11. public class User implements Cloneable {
  12.     private int age;
  13.     private String name;
  14.     //用戶地址信息
  15.     private UserAddress userAddress;
  16.     //getter setter 省略
  17.     @Override
  18.     protected Object clone() throws CloneNotSupportedException { 
  19.         return super.clone();
  20.     }
  21. }
  22. //測(cè)試
  23. public class UserTest {
  24.     public static void main(String[] args) throws Exception {
  25.         User user = new User();
  26.         user.setAge(20);
  27.         user.setName("田維常");
  28.         UserAddress userAddress = new UserAddress("貴州", "梵凈山");
  29.         user.setUserAddress(userAddress);
  30.         User clone = (User) user.clone();
  31.         System.out.println("克隆前后UserAddress比較:" + (user.getUserAddress() == clone.getUserAddress()));
  32.     }
  33. }

輸出結(jié)果

 
 
 
 
  1. 克隆前后 UserAddress 比較:true

兩個(gè)對(duì)象屬性 UserAddress 指向的是同一個(gè)地址。

這就是所謂的淺克隆,只是克隆了對(duì)象,對(duì)于該對(duì)象的非基本類型屬性,仍指向原來(lái)對(duì)象的屬性所指向的對(duì)象的內(nèi)存地址。

關(guān)系如下:

深克隆

關(guān)于深克隆,我們來(lái)用一個(gè)很經(jīng)典的案例,西游記里的孫悟空。一個(gè)孫悟空能變成n多個(gè)孫悟空,手里都會(huì)拿著一個(gè)金箍棒。

按照前面的淺克隆,結(jié)果就是:孫悟空倒是變成很多孫悟空,但是金箍棒用的是同一根。

深克隆的結(jié)果是:孫悟空變成了很多個(gè),金箍棒也變成很多個(gè)根。

下面我們用代碼來(lái)實(shí)現(xiàn):

 
 
 
 
  1. //猴子,有身高體重和生日
  2. public class Monkey {
  3.     public int height;
  4.     public int weight;
  5.     public Date birthday;
  6. }

孫悟空也是猴子,兵器 孫悟空有個(gè)金箍棒:

 
 
 
 
  1. import java.io.Serializable;
  2. //孫悟空的金箍棒
  3. public class JinGuBang implements Serializable{
  4.     public float  h=100;
  5.     public float  d=10;
  6.     //金箍棒變大
  7.     public void big(){
  8.         this.h *=10;
  9.         this.d *=10;
  10.     }
  11.     //金箍棒變小
  12.     public void small(){
  13.         this.h /=10;
  14.         this.d /=10;
  15.     }
  16. }

齊天大圣孫悟空:

 
 
 
 
  1. import java.io.*;
  2. import java.util.Date;
  3. //孫悟空有七十二變,拔猴毛生成一個(gè)金箍棒
  4. //使用JDK的克隆機(jī)制,
  5. //實(shí)現(xiàn)Cloneable并重寫clone方法
  6. public class QiTianDaSheng extends Monkey implements Cloneable, Serializable {
  7.     public JinGuBang jinGuBang;
  8.     public QiTianDaSheng() {
  9.         this.birthday = new Date();
  10.         this.jinGuBang = new JinGuBang();
  11.     }
  12.     @Override
  13.     protected Object clone() throws CloneNotSupportedException {
  14.         return this.deepClone();
  15.     }
  16.     //深克隆
  17.     public QiTianDaSheng deepClone() {
  18.         try {
  19.             //內(nèi)存中操作完成、對(duì)象讀寫,是通過(guò)字節(jié)碼直接操作
  20.             //與序列化操作類似
  21.             ByteArrayOutputStream bos = new ByteArrayOutputStream();
  22.             ObjectOutputStream oos = new ObjectOutputStream(bos);
  23.             oos.writeObject(this);
  24.             ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
  25.             ObjectInputStream bis = new ObjectInputStream(bais);
  26.             //完成一個(gè)新的對(duì)象,底層是使用new創(chuàng)建的一個(gè)對(duì)象
  27.             //詳情可以了解readObject方法
  28.             QiTianDaSheng qiTianDaSheng = (QiTianDaSheng) bis.readObject();
  29.             //每個(gè)猴子的生日不一樣,所以每次拷貝的時(shí)候,把生日改一下
  30.             qiTianDaSheng.birthday = new Date();
  31.             return qiTianDaSheng;
  32.         } catch (Exception ex) {
  33.             ex.printStackTrace();
  34.             return null;
  35.         }
  36.     }
  37.     //淺克隆,就是簡(jiǎn)單的賦值
  38.     public QiTianDaSheng shalllowClone(QiTianDaSheng target) {
  39.         QiTianDaSheng qiTianDaSheng = new QiTianDaSheng();
  40.         qiTianDaSheng.height = target.height;
  41.         qiTianDaSheng.weight = target.weight;
  42.         qiTianDaSheng.jinGuBang = target.jinGuBang;
  43.         qiTianDaSheng.birthday = new Date();
  44.         return qiTianDaSheng;
  45.     }
  46. }

接著我們就來(lái)測(cè)試一下:

 
 
 
 
  1. public class DeepCloneTest {
  2.     public static void main(String[] args) {
  3.         QiTianDaSheng qiTianDaSheng = new QiTianDaSheng();
  4.         try {
  5.             QiTianDaSheng newObject = (QiTianDaSheng) qiTianDaSheng.clone();
  6.             System.out.print("深克隆后 ");
  7.             System.out.println("金箍棒是否一直:" + (qiTianDaSheng.jinGuBang == newObject.jinGuBang));
  8.             
  9.         } catch (Exception ex) {
  10.             ex.printStackTrace();
  11.         }
  12.         
  13.         QiTianDaSheng newObject=qiTianDaSheng.shalllowClone(qiTianDaSheng);
  14.         System.out.print("淺克隆后 ");
  15.         System.out.println("金箍棒是否一直:" + (qiTianDaSheng.jinGuBang == newObject.jinGuBang));
  16.     }
  17. }

輸出結(jié)果為:

 
 
 
 
  1. 深克隆后 金箍棒是否一直:false
  2. 淺克隆后 金箍棒是否一直:true

結(jié)論

深克隆后每個(gè)孫悟空都有自己的金箍棒,而淺克隆后每個(gè)孫悟空用的金箍棒實(shí)質(zhì)上還是同一根。

總結(jié)

切記:深和淺,指的是克隆對(duì)象里的屬性(引用類型)是否指向同一個(gè)內(nèi)存地址。

為了更深刻的理解深克隆和淺克隆,我們回答文中的簡(jiǎn)歷拷貝的故事。

  • 深拷貝:拷貝一份簡(jiǎn)歷,然后對(duì)簡(jiǎn)歷中的信息進(jìn)行修改成自己的
  • 淺拷貝:拷貝一份簡(jiǎn)歷,簡(jiǎn)歷內(nèi)容完全不變

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

  • Java 原型模式基于內(nèi)存二進(jìn)制流復(fù)制,比直接 new 的性能會(huì)更好一些。
  • 可以利用深克隆保存對(duì)象狀態(tài),存一份舊的(克隆出來(lái)),在對(duì)其修改,可以充當(dāng)一個(gè)撤銷功能。

缺點(diǎn):

  • 需要配置 clone 方法,改造時(shí)需要對(duì)已有類進(jìn)行修改,違背 “開(kāi)閉原則”。
  • 如果對(duì)象間存在多重嵌套引用時(shí),每一層都需要實(shí)現(xiàn)克隆。

我們從原型模式的定義,使用場(chǎng)景,真實(shí)案例、淺克隆、深克隆、優(yōu)缺點(diǎn)等方面,對(duì)原型模式進(jìn)行了一個(gè)全面的講解。

一句話總結(jié):

一份簡(jiǎn)歷,全班同學(xué)用

本文轉(zhuǎn)載自微信公眾號(hào)「Java后端技術(shù)全?!梗梢酝ㄟ^(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java后端技術(shù)全棧公眾號(hào)。


名稱欄目:五分鐘掌握原型模式
URL鏈接:http://www.5511xx.com/article/djesggs.html