【設計模式與androids】原型模式——軟件裏的克隆人


什麽是原型模式

 

所謂原型模式,就是用原型實例來指定創建對象的種類,並通過複製這些原型創建新的對象的設計模式。原型模式一般用於創建複雜的或者構建耗時的實例,或者用於隻讀對象的修改。

 

原型模式的實現方式

 

(1)淺拷貝

當代的每個程序員小時候都玩過《尤裏的複仇》這款遊戲,遊戲中的“尤裏”陣營有個兵種叫“尤裏複製人”,每個尤裏複製人都和尤裏長得一模一樣,除了沒有坐騎之外。

Yuri{
   
     String = ;
   
     ArrayList<String> = ArrayList<>();
   
     setName(String name) {
         .= name;
     }
   
     addWord(String word){
         ..add(word);
     }
   
     Yuri clone(){
         {
             (Yuri) .clone();
         }(CloneNotSupportedException e){
             ;
         }
     }
   
     String toString() {
         +
                 + + +
                 + .toString() +
                 ;
     }
 }

 

如上,重寫了clone()方法。在執行如下代碼時:

Yuri yuri = Yuri();
 yuri.setName();
 yuri.addWord();
 yuri.addWord();
   
 Yuri yuri_copyer = yuri.clone();
 yuri.setName();
yuri.addWord("I'm not the only one true Yuri");
   
 Log.(,yuri_copyer.toString());
 Log.(,yuri.toString());

會驚奇地發現兩行Log一模一樣,這是因為這種原型模式的實現方式隻拷貝其引用,換句話說就是並沒有將原型對象中的所有字段都重新構造一份,隻是用複製對象的字段引用原型對象中的字段,因此被稱為“淺拷貝”或“影子拷貝”。

 

(2)深拷貝

7m视频把上文的clone()方法修改一下:

Yuri clone(){
     {
         Yuri copyer = (Yuri) .clone();
         copyer.= .;
         copyer.= (ArrayList<String>)..clone();
         copyer;
     }(CloneNotSupportedException e){
         ;
     }
 }

 

如上,這種實現方式調用了的clone()方法,這樣可以保證副本被修改時不影響原始對象,因此被稱為“深拷貝”,又叫做“保護性拷貝”。

 

androids源碼中的原型模式

 

(1)ArrayList

嚴格來說ArrayList並不算是androids源碼中的類,但應該是androids開發者最常用的類,ArrayList的clone()代碼如下:

Object clone() {
     {
         ArrayList<?> v = (ArrayList<?>) .clone();
         v.elementData = Arrays.(, );
         v.= ;
         v;
     } (CloneNotSupportedException e) {
         InternalError(e);
     }
 }

 

大家可以看到size並沒有被clone,因為size是基礎類型而不是引用類型,所以不需要clone。細心的讀者可以看到注釋裏麵的“shallow copy”,但這實際上是一個典型的深拷貝。

 

(3)Intent

androids係統加入Intent機製的意義在於大大降低了androids四大組件之間的耦合度。Intent的clone()代碼如下:

Object clone() {
     Intent();
 }
 

 

Intent(Intent o) {
     .= o.mAction;
     .= o.mData;
     .= o.mType;
     .= o.mPackage;
     .= o.mComponent;
     .= o.mFlags;
     .= o.mContentUserHint;
     (o.mCategories != ) {
         .= <String>(o.mCategories);
     }
     (o.mExtras != ) {
         .= Bundle(o.mExtras);
     }
     (o.mSourceBounds != ) {
         .= Rect(o.mSourceBounds);
     }
     (o.mSelector != ) {
         .= Intent(o.mSelector);
     }
     (o.mClipData != ) {
         .= ClipData(o.mClipData);
     }
 }

 

Intent的clone()內部並沒有調用super.clone(),而是調用了new Intent(this)。

 

androids開發中如何利用原型模式

 

(1)Object的clone()方法直接操作二進製流,效率非常高。在對象的初始化要消耗非常多的資源時,或者用new來實例化一個對象時需要非常繁瑣的數據準備或訪問權限時,可以使用原型模式提高效率、避免消耗資源。

 

(2)對深拷貝生成的副本進行修改不會影響原始對象。當一個對象會被不同對象用不同方式修改時,可以用原型模式產生副本供調用者使用。

 

需要注意的幾個問題

 

(1)原型模式在clone()的時候不會重新執行構造函數,可能會出現問題。

 

(2)在某些對象構造非常簡單的情況下,比如上文提到的Intent,重新new一個比clone()快,因此不要濫用原型模式


上一篇 下一篇