【原創·教程·連載】《Android之大話設計模式》–設計模式之結構型模式 第九章:享元模式 簡訊可以這樣發

來源:互聯網
上載者:User
<大話設計模式>本教程說明及著作權聲明

國士工作室是一支專註於Android平台企業級應用開發的技術團隊,致力於做中國最棒的Android應用程式開發機構,提供最棒的Android企業級應用開發培訓服務。

企業培訓和開發合作官方連絡方式:

     電話:18610086859

     Email:hiheartfirst@gmail.com

     QQ:1740415547

國士工作室 有你更美好!

l 該文檔參考和使用了網路上的免費開放的圖片和內容,並以免費開放的方式發布,希望為移動互連網和智能手機時代貢獻綿薄之力!可以隨意轉載,但不得使用該文檔謀利。

l 如果對該文檔有任何疑問或者建議,請進入官方部落格

   http://www.cnblogs.com/guoshiandroid/留言或者直接與國士工作室聯絡(後附連絡方式),我們會謹慎參考您的建議並根據需要對本文檔進行修改,以造福更多開發人員!

l 《大話設計模式》的最新及完整內容會在國士工作室官方部落格定期更新,請訪問國士工作室部落格

http://www.cnblogs.com/guoshiandroid/擷取更多更新內容。

 

享元模式 簡訊可以這樣發 

享元模式應用情境舉例 

GG每天給MM至少發一條簡訊,而且每天入睡前是必有一條簡訊的,往往是一些瑣事和一些比較肉麻的情話。開始的一個月,GG還對此是樂不可支,隨著時間的推移,那些肉麻的話說了很多遍,自己也覺得厭煩了,而且更讓人不可忍耐的是這些肉麻的情話每次都要重複的輸入。GG把這一煩心事告訴了自己的好友K,K說,“你這個大傻瓜,怎麼不把一些你常用的話存放在你的手機中,這樣,要用的時候,直接拿來用就行了”,傻GG一聽,頓時覺得醍醐灌頂,於是立即在手機中存放入了“寶貝兒,晚安喔”、“你是我天使”,“寶貝兒,我永遠的愛你”等話語。

享元模式解釋: 

享元模式(Flyweight Pattern)是通過使用共用的方式,達到高效地支援大量的細粒度對象。它的目的就是節省佔用的空間資源,從而實現系統效能的改善。

享元的英文是Flyweight,它是一個來自於體育方面的專業用語,在拳擊、摔跤和舉重比賽中特指最輕量的層級。把這個單詞移植到軟體工程裡面,也是用來表示特別小的對象,即細粒度對象。至於為什麼我們把Flyweight翻譯為“享元”,可以理解為共用元對象,也就是共用細粒度對象。

    英文定義為:Use sharing to support large numbers of fine-grained objects
efficiently.

享元模式的UML圖: 

       享元模式涉及以下的角色:

       抽象享元(Flyweight)角色: 它是所有具體享元類的超類。為這些類規定出需要實現的公用介面,那些需要外蘊狀態(External State)的操作可以通過方法的參數傳入。抽象享元的介面使得享元變得可能,但是並不強制子類實行共用,因此並非所有的享元對象都是可以共用的。

     具體享元(ConcreteFlyweight)角色:具體享元類實現了抽象享元類所規定的介面。如果有內蘊狀態(Internal State)的話,必須負責為內蘊狀態提供儲存空間。享元對象的內蘊狀態必須與對象所處的周圍環境無關,從而使得享元對象可以在系統內共用。有時候具體享元類又稱為單純具體享元類,因為複合享元類是由單純具體享元角色通過複合而成的。

不能共用的具體享元類(UnsharableFlyweight): 不能共用的享元類,又叫做複合享元類。一個複合享元對象是由多個單享元對象組成,這些組成的對象是可以共用的,但是複合享元類本身並不能共用。

享元工廠類(FlyweightFactory): 享元工廠類負責建立和管理享元對象。當一個用戶端對象請求一個享元對象的時候,享元工廠需要檢查系統中是否已經有一個符合要求的享元對象,如果已經有了,享元工廠角色就應當提供這個已有的享元對象;如果系統中沒有適當的享元對象的話,享元工廠角色就應當建立一個新的合適的享元對象。

客戶類(Client): 客戶類需要自行儲存所有享元對象的外蘊狀態。

享元模式的UML圖如下所示:

享元模式深入分析

       它通過與其他類似對象共用資料來減小記憶體佔用。

       享元對象的第一類狀態稱為內蘊狀態(Internal State)。它不會隨環境改變而改變,儲存在享元對象內部,因此內蘊狀態是可以共用的,對於任何一個享元對象來講,它的值是完全相同的。

享元對象的第二類狀態稱為外蘊狀態(External
State)。它會隨環境的改變而改變,因此是不可以共用的狀態,對於不同的享元對象來講,它的值可能是不同的。享元對象的外蘊狀態必須由用戶端儲存,在享元對象被建立之後,需要使用的時候再傳入到享元對象內部。所以享元的外蘊狀態與內蘊狀態是兩類相互獨立的狀態,彼此沒有關聯。

享元模式使用情境分析及代碼實現: 

       在上面的使用情境中,儲存在GG手機中的肉麻簡訊就是具體的享元對象。

       UML模型圖如下所示:

 

建立抽象享元角色:

package com.diermeng.designPattern.Flyweight;

/*

 * 抽象享元角色

 */

public interface BaseSweetWord {

    //顯示方法

    public void display();

}

 

建立具體享元角色:

package com.diermeng.designPattern.Flyweight.impl;

import com.diermeng.designPattern.Flyweight.BaseSweetWord;

 

/*

 * 具體的享元類

 */

public class MySweetWord implements BaseSweetWord{

    //具體享元屬性

    private String mychar;

 

    public MySweetWord() {}

    //具有執行個體化屬性功能的構造方法

    public MySweetWord(String mychar) {

       this.mychar = mychar;

    }

 

    //對現實功能的具體實現

    public void display() {

       System.out.println(mychar);

    }

}

 

建立享元工廠類:

package com.diermeng.designPattern.Flyweight.impl;

 

import java.util.HashMap;

import java.util.Map;

 

import com.diermeng.designPattern.Flyweight.BaseSweetWord;

 

/*

 * 享元工廠類

 */

public class MySweetWordFactory {

    //享元對象的集合

    private
Map<String,BaseSweetWord> pool;

 

    //建構函式 執行個體化享元對象的集合

    public MySweetWordFactory() {

       pool = new HashMap<String,BaseSweetWord>();

    }

 

    //擷取享元對象 如果集合中不存在該享元對象 就建立這個對象

    public BaseSweetWord
getMyCharacter(String character) {

       BaseSweetWord myChar = pool.get(character);

       if(myChar == null) {

           myChar = new
MySweetWord(character);

           pool.put(character, myChar);

       }

       return myChar;

    }

}

最後我們建立測試用戶端:

package com.diermeng.designPattern.Flyweight.client;

 

import com.diermeng.designPattern.Flyweight.BaseSweetWord;

import
com.diermeng.designPattern.Flyweight.impl.MySweetWordFactory;

 

/*

 * 享元模式測試用戶端

 */

public class FlyweightTest {

 

    public static void main(String[] args) {

       //建立享元工廠

       MySweetWordFactory factory = new
MySweetWordFactory();

 

       //從具體的享元工廠中取出相應的MyCharacter

       BaseSweetWord myChar1 =
factory.getMyCharacter("寶貝兒,晚安喔");

       BaseSweetWord myChar2 =
factory.getMyCharacter("你是我天使");

       BaseSweetWord myChar3 = factory.getMyCharacter("寶貝兒,晚安喔");

       BaseSweetWord myChar4 =
factory.getMyCharacter("寶貝兒,我永遠的愛你");

 

       myChar1.display();

       myChar2.display();

       myChar3.display();

       myChar4.display();

 

       if(myChar1 == myChar3) {

           System.out.println("哈哈,恭喜!我們是同一句話,直接複製就行了!");

       } else {

           System.out.println("哎呀,我們不是同一句話!");

       }

    }

 

}

輸出的結果如下:

寶貝兒,晚安喔

你是我天使

寶貝兒,晚安喔

寶貝兒,我永遠的愛你

哈哈,恭喜!我們是同一句話,直接複製就行了!

 

享元模式的優缺點分析: 

       優點:

使用享元模式可以降低記憶體中對象的數量,從而為系統節省大量的記憶體空間。

缺點:

享元模式使得系統更加複雜,因為為了使對象可以共用,需要將一些狀態外部化,這使得程式的邏輯複雜化。而且,由於享元工廠需要維護所有的享元對象,此時,如果要維護的享元對象很多的話,在尋找具體的享元對象的時候就要消耗大量的時間,換句話說,享元模式是一種以時間換空間的模式。

享元模式的實際應用簡介: 

享元模式在一般的項目開發中並不常用,而是常常應用於系統底層的開發,以便解決系統的效能問題。

Java中的String類型就是使用了享元模式。

如果在Java中已經建立了一個字串對象string1,那麼下次再建立相同的字串string2的時候,系統只是把string2的引用指向string1所引用的具體對象,這就實現了相同字串在記憶體中的共用。如果每次執行string1=“abc”操作的時候,都建立一個新的字串對象的話,那麼記憶體的開銷會很大。

如果大家有興趣的話,可以用下面的程式進行測試,就會知道string1和string2的引用是否一致:

String string1= "愛你一萬年,愛你的心永不改變";

String string2= "愛你一萬年,愛你的心永不改變";

//“==”用來判斷兩個對象是否是同一個,equals判斷字串的值是否相等

if( string1 == string2 ){

System.out.println("兩者一樣");

}else{

System.out.println("兩者不一樣");

}

程式運行後,輸出的結果為“兩者一樣”,這說明String類的設計採用了享元模式。如果string1的內容發生了變化,比如執行了string1 += "讓我們結婚吧!"的語句,那麼s1與s2的引用將不再一致。

我們額外的談一下PHP中String的處理。作為一種弱類型語言,PHP的字串類型是一種基本類型,不是對象。另外,它的執行方式與Java有明顯區別,每一個指令檔執行開始,將會裝入所有需要的資源;執行結束後,又將佔用的資源就立即全部釋放,所以它基本上不會產生類似的效能問題,它的字串處理的設計,自然也使用不到享元模式。

溫馨提示: 

 

       物件導向雖然很好地解決了抽象性的問題,但是對於一個實際啟動並執行軟體系統,我們還需要考慮物件導向的代價問題,享元模式解決的就是物件導向的代價問題。享元模式採用對象共用的做法來降低系統中對象的個數,從而降低細粒度對象給系統帶來的記憶體壓力。

在具體實現方面,我們要注意對象狀態的處理,一定要正確地區分對象的內蘊狀態和外蘊狀態,這是實現享元模式的關鍵所在。

享元模式的優點在於它大幅度地降低記憶體中對象的數量。為了做到這一點,享元模式也付出了一定的代價:

1、享元模式為了使對象可以共用,它需要將部分狀態外部化,這使得系統的邏輯變得複雜。

2、享元模式將享元對象的部分狀態外部化,而讀取外部狀態使得已耗用時間會有所加長。

另外,還有一個比較令人關心的問題:到底系統需要滿足什麼樣的條件才能使用享元模式。對於這個問題,總結出以下幾點:

1、一個系統中存在著大量的細粒度對象;

2、這些細粒度對象耗費了大量的記憶體。

3、這些細粒度對象的狀態中的大部分都可以外部化;

4、這些細粒度對象可以按照內蘊狀態分成很多的組,當把外蘊對象從對象中剔除時,每一個組都可以僅用一個對象代替。

5、軟體系統不依賴於這些對象的身份,換言之,這些對象可以是不可分辨的。

滿足以上的這些條件的系統可以使用享元對象。最後,使用享元模式需要維護一個記錄了系統已有的所有享元的雜湊表,也稱之為對象池,而這也需要耗費一定的資源。因此,應當在有足夠多的享元執行個體可供共用時才值得使用享元模式。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.