原型模式(Prototype)

​1、原型模式介紹html

原型模式:原型模式就是從一個對象再建立另一個可定製的對象,並且不須要知道任何建立的細節。java

所謂原型模式,就是java中的克隆技術,以某個對象爲原型。複製出新的對象。顯然新的對象具有原型對象的特色。效率高(避免了從新執行構造過程步驟)設計模式

克隆相似於new,但和new不一樣。new建立新的對象屬性採用的是默認值。克隆出來的對象的屬性值徹底和原型對象相同。而且克隆出的新對象不會影響原型對象,克隆後。還能夠再修改克隆對象的值。數組

要實現原型模式,必須實現Cloneable接口,而這個接口裏面是空的。框架

Cloneable接口是一個空接口,使用Cloneable接口都不用導入包。而clone方法是屬於Object對象的。若是要克隆某個對象的話必須實現Cloneable接口ide

1
2
3
4
5
6
7
@author   unascribed
  @see      java.lang.CloneNotSupportedException
  @see      java.lang.Object#clone()
  @since    JDK1. 0
  */
public  interface  Cloneable {
}

重寫Object對象的clone方法,clone方法爲本地方法。效率比較高學習

1
protected  native  Object clone()  throws  CloneNotSupportedException;

若是咱們要克隆某個對象有淺克隆和深克隆測試

淺克隆:copy該對象,而後保留該對象原有的引用。也就是說不克隆該對象的屬性。this

深克隆:copy該對象,而且把該對象的全部屬性也克隆出一份新的。
spa

2、代碼實現

一、淺克隆代碼實現:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
  * 原型模式:淺克隆
  * Cloneable是一個空接口(標記接口),是一個規範。可是若是要克隆這個類對象的話必須實現Cloneable接口
  */
public  class  Sheep  implements  Cloneable{
     private  String sname;
     private  Date birthday;
     
     /**
      * 重寫Object對象的clone方法
      */
     @Override
     protected  Object clone()  throws  CloneNotSupportedException {
         //直接調用Object對象的clone方法
         Object obj =  super .clone();
         return  obj;
     }
     //省略get,set方法和構造方法
     
}
 
/**
  * 測試原型模式(淺克隆)
  */
public  class  Test {
     public  static  void  main(String[] args)  throws  Exception {
         Date date =  new  Date(1274397294739L);
         Sheep s1 =  new  Sheep( "原型羊" ,date);
         Sheep s2 = (Sheep) s1.clone(); //克隆一個羊
         System.out.println(s1);
         System.out.println(s1.getSname());
         System.out.println( "原日期:" +s1.getBirthday());
         date.setTime(34732834827389L); //改變原有date的值
         System.out.println( "改變後的日期:" +date.toString());
         
         //克隆羊的信息
         System.out.println( "---------------------------------" );
         System.out.println(s2);
         System.out.println(s2.getSname());
         System.out.println(s2.getBirthday()); //此時的birthday日期使用的是改變後的日期對象引用
     }
}

最後的結果爲:克隆的對象仍然保留了原有對象的引用,值隨着改變而改變

1
2
3
4
5
6
7
8
com.fz.prototype.Sheep @153f67e
原型羊
原日期:Fri May  21  07 : 14 : 54  CST  2010
改變後的日期:Mon Aug  22  17 : 40 : 27  CST  3070
---------------------------------
com.fz.prototype.Sheep @18f51f
原型羊
Mon Aug  22  17 : 40 : 27  CST  3070

 

二、深克隆代碼實現:克隆對象的同時,把該對象的屬性也連帶着克隆出新的。

深克隆只須要在clone方法中將該對象的屬性也克隆便可

1
2
3
4
5
6
7
8
9
10
11
12
/**
  * 重寫Object對象的clone方法
  */
@Override
protected  Object clone()  throws  CloneNotSupportedException {
     //直接調用Object對象的clone方法
     Object obj =  super .clone();
     //深克隆:把對象下的全部屬性也克隆出來
     Sheep22 s = (Sheep22) obj;
     s.birthday = (Date)  this .birthday.clone();
     return  s;
}

測試代碼不變,結果則會變了。克隆了以後把原來的日期改變後,克隆的對象2的屬性則不會被影響。

1
2
3
4
5
6
7
8
com.fz.prototype.Sheep2 @15bdc50
原型羊
原日期:Fri May  21  07 : 14 : 54  CST  2010
改變後的日期:Mon Aug  22  17 : 40 : 27  CST  3070
---------------------------------
com.fz.prototype.Sheep2 @18f51f
原型羊
Fri May  21  07 : 14 : 54  CST  2010

 

三、經過序列化和反序列化來實現深克隆對象:序列化須要原型對象實現Serializable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import  java.io.ByteArrayInputStream;
import  java.io.ByteArrayOutputStream;
import  java.io.ObjectInputStream;
import  java.io.ObjectOutputStream;
import  java.util.Date;
 
/**
  * 測試原型模式(利用序列化和反序列化實現深克隆)
  */
public  class  Test3 {
     public  static  void  main(String[] args)  throws  Exception {
         Date date =  new  Date(1274397294739L);
         Sheep s1 =  new  Sheep( "原型羊" ,date);
//      Sheep s2 = (Sheep) s1.clone();//克隆一個羊
         
         //使用序列化和反序列化實現深複製
         //一、將s1對象序列化爲一個數組
         //經過ObjectOutputStream流將s1對象讀出來給ByteArrayOutputStream流
         ByteArrayOutputStream bos =  new  ByteArrayOutputStream();
         ObjectOutputStream    oos =  new  ObjectOutputStream(bos);
         oos.writeObject(s1);
         //ByteArrayOutputStream流將對象信息轉成byte數組,這樣byte數組裏就包含了對象的數據
         byte [] bytes = bos.toByteArray();
         
         //二、將字節數組中的內容反序列化爲一個Sheep對象
         //經過ByteArrayInputStream流讀入bytes字節數組中數據,而後傳給ObjectInputStream對象輸入流
         ByteArrayInputStream bis =  new  ByteArrayInputStream(bytes);
         ObjectInputStream    ois =  new  ObjectInputStream(bis);
         //經過ObjectInputStream返回一個Sheep對象
         Sheep s2 = (Sheep) ois.readObject();
 
         //原型羊的信息
         System.out.println(s1);
         System.out.println( "原日期:" +s1.getBirthday());
         date.setTime(34732834827389L); //改變原有date的值
         System.out.println( "改變後的日期:" +date.toString());
         //克隆羊的信息
         System.out.println( "---------------------------------" );
         System.out.println(s2);
         System.out.println(s2.getBirthday());
     }
}

經過序列化和反序列化的結果,最終結果仍是和深克隆同樣。

1
2
3
4
5
6
7
8
9
10
11
com.fz.prototype.Sheep @1a116c9
 
原日期:Fri May  21  07 : 14 : 54  CST  2010
 
改變後的日期:Mon Aug  22  17 : 40 : 27  CST  3070
 
---------------------------------
 
com.fz.prototype.Sheep @7eb6e2
 
Fri May  21  07 : 14 : 54  CST  2010

 

3、測試克隆對象的效率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package  com.fz.prototype;
/**
  * 測試clone對象的效率
  */
public  class  TestClone {
     //new 對象
     public  static  void  testNew( int  size){
         long  start = System.currentTimeMillis();
         for  ( int  i =  0 ; i < size; i++) {
             Laptop l =  new  Laptop();
         }
         long  end = System.currentTimeMillis();
         System.out.println( "new 對象耗時:" +(end-start));
     }
     //clone 對象
     public  static  void  testClone( int  size){
         long  start = System.currentTimeMillis();
         Laptop l =  new  Laptop();
         for  ( int  i =  0 ; i < size; i++) {
             try  {
                 Laptop temp = (Laptop) l.clone();
             catch  (CloneNotSupportedException e) {
                 e.printStackTrace();
             }
         }
         long  end = System.currentTimeMillis();
         System.out.println( "clone 對象耗時:" +(end-start));
     }
     public  static  void  main(String[] args) {
         testNew( 1000 );
         testClone( 1000 );
     }
}
 
class  Laptop  implements  Cloneable{
     public  Laptop() {
         //模擬建立Laptop對象的時候比較耗時
         try  {
             Thread.sleep( 10 );
         catch  (InterruptedException e) {
             e.printStackTrace();
         }
     }
     @Override
     protected  Object clone()  throws  CloneNotSupportedException {
         return  super .clone();
     }
}

最後結果爲:

new 對象耗時:10063

clone 對象耗時:10

 

4、使用場景

原型模式適用場景:若是某個對象new的過程當中很耗時,則能夠考慮使用原型模式。

Spring框架中bean對象的建立就兩種模式:單例模式或者原型模式

 

 



Java23種設計模式學習筆記【目錄總貼】

參考資料:

  大話設計模式(帶目錄完整版).pdf

  HEAD_FIRST設計模式(中文版).pdf

  尚學堂_高淇_java300集最全視頻教程_【GOF23設計模式】

相關文章
相關標籤/搜索