国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android編程設計模式之原型模式實例詳解

2019-10-22 18:19:13
字體:
來源:轉載
供稿:網友

本文實例講述了Android編程設計模式之原型模式。分享給大家供大家參考,具體如下:

一、介紹

原型模式是一個創建型的模式。原型二字表明了該模型應該有一個樣板實例,用戶從這個樣板對象中復制出一個內部屬性一致的對象,這個過程也就是我們俗稱的“克隆”。被復制的實例就是我們所稱的“原型”,這個原型也是可定制的。原型模型多用于創建復雜的或者構造耗時的實例,因為這種情況下,復制一個已經存在的實例可使程序運行更高效。

二、定義

用原型實例指定創建對象的種類,并通過拷貝這些原型創建新的對象。

三、使用場景

(1)類初始化需要消耗非常多的資源,這個資源包括數據、硬件資源等,通過原型拷貝避免這些消耗。

(2)通過new產生一個對象需要非常繁瑣的數據準備或訪問權限,這時可以使用原型模式。

(3)一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用,即保護性拷貝。

需要注意的是,通過實行Cloneable接口的原型模式在調用clone函數構造實例時并不一定比通過new操作速度快,只有當通過new構造對象較為耗時或者說成本較高時,通過clone方法才能夠獲得效率上的提升。因此,在使用Cloneable時需要考慮構建對象的成本以及做一些效率上的測試。當然,實現原型模式也不一定非要實現Cloneable接口,也有其他的實現方式,這里將會對這些一一說明。

四、原型模型的UML類圖

Android,原型模式,設計模式

圖中角色介紹:

Client:客戶端用戶。

Prototype:抽象類或者接口,聲明具備clone能力。

ConcretePrototype:具體的原型類。

五、原型模式的簡單實現

下面以簡單的文檔拷貝為例來演示一下簡單的原型模式,我們在這個例子中首先創建了一個文檔對象,即WordDocument,這個文檔中含有文字和圖片。用戶經過了長時間的內容編輯后,打算對該文檔做進一步的編輯,但是,這個編輯后的文檔是否會被采用還不確定,因此,為了安全起見,用戶需要將當前文檔拷貝一份,然后再在文檔副本上進行修改,這與《Effective Java》一書中提到的保護性拷貝有些類似,如此,這個原始文檔就是我們上述所說的樣板實例,也就是將要被“克隆”的對象,我們成為原型:

示例代碼:

/** * 文檔類型,扮演的是ConcretePrototype角色,而cloneable是代表prototype角色 */public class WordDocument implements Cloneable { //文本 private String mText; //圖片名列表 private ArrayList<String> mImages = new ArrayList<String>(); public WordDocument(){  System.out.println("-------- WordDocument構造函數 --------"); } public String getText(){  return this.mText; } public void setText(String text){  this.mText = text; } public ArrayList<String> getImages(){  return this.mImages; } public void setImages(ArrayList<String> images){  this.mImages = images; } public void addImage(String img){  this.mImages.add(img); } /**  * 打印文檔  */ public void showDocument(){  System.out.println("-------- Word Content Start --------");  System.out.println("Text : " + this.mText);  System.out.println("Images List : ");  for(String image : mImages){   System.out.println("image name : " + image);  }  System.out.println("-------- Word Content End --------"); } @Override protected WordDocument clone(){  try{   WordDocument doc = (WordDocument)super.clone();   doc.mText = this.mText;   doc.mImages = this.mImages;   return doc;  }catch(Exception e){}  return null; }}

執行方法:

public static void main(String[] args) throws IOException {  //1.構建文檔對象  WordDocument originDoc = new WordDocument();  //2.編輯文檔,添加圖片等  originDoc.setText("這是一篇文檔");  originDoc.addImage("圖片一");  originDoc.addImage("圖片二");  originDoc.addImage("圖片三");  originDoc.showDocument();  //以原始文檔為原型,拷貝一份副本  WordDocument doc2 = originDoc.clone();  doc2.showDocument();  //修改文檔副本  doc2.setText("這是修改過的Doc2文本");  doc2.addImage("這是新添加的圖片");  originDoc.showDocument();  doc2.showDocument();}

執行結果:

-------- WordDocument構造函數 --------//originDoc-------- Word Content Start --------Text : 這是一篇文檔Images List :image name : 圖片一image name : 圖片二image name : 圖片三-------- Word Content End --------//doc2-------- Word Content Start --------Text : 這是一篇文檔Images List :image name : 圖片一image name : 圖片二image name : 圖片三-------- Word Content End --------//副本修改后originDoc-------- Word Content Start --------Text : 這是一篇文檔Images List :image name : 圖片一image name : 圖片二image name : 圖片三image name : 這是新添加的圖片-------- Word Content End --------//副本修改后doc2-------- Word Content Start --------Text : 這是修改過的Doc2文本Images List :image name : 圖片一image name : 圖片二image name : 圖片三image name : 這是新添加的圖片-------- Word Content End --------

這里我們發現通過修改doc2后,只是影響了originDoc的mImages,而沒有改變mText。

六、淺拷貝和深拷貝

上述原型模式的實現實際上只是一個淺拷貝,也稱影子拷貝,這份拷貝實際上并不是將原始的文檔的所有字段都重新構造了一份,而是副本文檔的字段引用原始文檔的字段,如下圖:

Android,原型模式,設計模式

細心的讀者可能從上面的結果中發現,最后兩個文檔信息輸出是一致的。我們在doc2添加了一張圖片,但是,同時也顯示在originDoc中,這是怎么回事呢?學習過C++的讀者都會有比較深刻的體會,這是因為上文中WordDocument的clone方法中只是簡單的進行了淺拷貝,引用類型的新對象doc2.mImages只是單純的指向了this.mImages引用,并沒有重新構造一個mImages對象,然后將原始文檔中的圖片添加到新的mImages對象中,這樣就導致doc2.mImages與原始文檔中的是同一個對象,因此,修改了其中一個文檔中的圖片,另一個文檔也會受影響。那么如何解決這個問題呢?答案就是采用深拷貝,即在拷貝對象時,對于引用型的字段也要采用拷貝的形式,而不是單純引用的形式。

clone方法修改如下(其他不變):

@Overrideprotected WordDocument clone(){  try{   WordDocument doc = (WordDocument)super.clone();   doc.mText = this.mText;   //對mImages對象也調用clone()函數,進行深拷貝   doc.mImages = (ArrayList<String>)this.mImages.clone();   return doc;  }catch(Exception e){}  return null;}

修改后在執行上述代碼的結果是:

-------- WordDocument構造函數 --------//originDoc-------- Word Content Start --------Text : 這是一篇文檔Images List :image name : 圖片一image name : 圖片二image name : 圖片三-------- Word Content End --------//doc2-------- Word Content Start --------Text : 這是一篇文檔Images List :image name : 圖片一image name : 圖片二image name : 圖片三-------- Word Content End --------//副本修改后originDoc-------- Word Content Start --------Text : 這是一篇文檔Images List :image name : 圖片一image name : 圖片二image name : 圖片三-------- Word Content End --------//副本修改后doc2-------- Word Content Start --------Text : 這是修改過的Doc2文本Images List :image name : 圖片一image name : 圖片二image name : 圖片三image name : 這是新添加的圖片-------- Word Content End --------

可以看出現在互不影響,這個叫做深拷貝。

接著上面的疑問,其實String類型在淺拷貝時和引用類型一樣,沒有單獨復制,而是引用同一地址,因為String沒有實現cloneable接口,也就是說只能復制引用。(這里我們可以查看源碼可以看到,而ArrayList實現了cloneable接口)但是當修改其中的一個值的時候,會新分配一塊內存用來保存新的值,這個引用指向新的內存空間,原來的String因為還存在指向他的引用,所以不會被回收,這樣,雖然是復制的引用,但是修改值的時候,并沒有改變被復制對象的值。

所以在很多情況下,我們可以把String在clone的時候和基本類型做相同的處理,只是在equals時注意一些就行了。

原型模式是非常簡單的一個模式,它的核心問題就是對原始對象進行拷貝,在這個模式的使用過程中需要注意的一點就是:深、淺拷貝的問題。在開發過程中,為了減少錯誤,作者建議使用該模式時盡量使用深拷貝,避免操作副本時影響原始對象的問題。

七、Android源碼中的原型模式

示例代碼:

Uri uri = Uri.parse("smsto:110");Intent intent = new Intent(Intent.ACTION_SEND,uri);intent.putExtra("sms_body", "The SMS text");//克隆Intent intent2 = (Intent)intent.clone();startActivity(intent2);

八、總結

原型模式本質上就是對象的拷貝,與C++中的拷貝構造函數有些類似,它們之間容易出現的問題也都是深拷貝、淺拷貝。使用原型模式可以解決構建復雜對象的資源消耗問題,能夠在某些場景下提升創建對象的效率。

優點:

(1)原型模式是在內存中二進制流的拷貝,要比直接new一個對象性能好很多,特別是要在一個循環體內產生大量對象時,原型模式可能更好的體現其優點。

(2)還有一個重要的用途就是保護性拷貝,也就是對某個對象對外可能是只讀的,為了防止外部對這個只讀對象的修改,通常可以通過返回一個對象拷貝的形式實現只讀的限制。

缺點:

(1)這既是它的優點也是缺點,直接在內存中拷貝,構造函數是不會執行的,在實際開發中應該注意這個潛在問題。優點是減少了約束,缺點也是減少了約束,需要大家在實際應用時考慮。

(2)通過實現Cloneable接口的原型模式在調用clone函數構造實例時并不一定比通過new操作速度快,只有當通過new構造對象較為耗時或者說成本較高時,通過clone方法才能夠獲得效率上的提升。

 

希望本文所述對大家Android程序設計有所幫助。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 杭锦旗| 泸定县| 阳新县| 兴仁县| 邯郸市| 吴堡县| 金塔县| 玉环县| 延安市| 湘西| 密云县| 右玉县| 北宁市| 固安县| 乌恰县| 安化县| 辽宁省| 茌平县| 太仆寺旗| 丰台区| 沅陵县| 新密市| 荥阳市| 旌德县| 合川市| 酒泉市| 永登县| 盐城市| 苍山县| 获嘉县| 田林县| 德格县| 南雄市| 从化市| 根河市| 永德县| 堆龙德庆县| 滦南县| 梨树县| 拉萨市| 沙洋县|