Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 《Android源碼設計模式解析與實戰》讀書筆記(二十二)

《Android源碼設計模式解析與實戰》讀書筆記(二十二)

編輯:關於android開發

《Android源碼設計模式解析與實戰》讀書筆記(二十二)


第二十二章、享元模式

享元模式是結構型設計模式之一,是對對象池的一種實現。就像它的名字一樣,共享對象,避免重復的創建。我們常用的String 就是使用了共享模式,所以String類型的對象創建後就不可改變,如果當兩個String對象所包含的內容相同時,JVM只創建一個String對象對應這兩個不同的對象引用。

1.定義

采用一個共享來避免大量擁有相同內容對象的開銷。使用享元模式可有效支持大量的細粒度對象。

2.使用場景

(1)系統中存在大量的相似對象。

(2)細粒度的對象都具備較接近的外部狀態,而且內部狀態與環境不關,也就是說對象沒有特定身份。

(3)需要緩沖池的場景。

PS:內部狀態與外部狀態:在享元對象內部並且不會隨著環境改變而改變的共享部分,可以稱之為享元對象的內部狀態,反之隨著環境改變而改變的,不可共享的狀態稱之為外部狀態。

3.UML類圖

這裡寫圖片描述

享元模式分為單純享元模式和復合享元模式,上圖是復合享元模式。

(1)Flyweight:享元對象抽象基類或者接口。

(2)ConcreateFlyweight:具體的享元對象,如果有內部狀態的話,必須負責為內部狀態提供存儲空間。

(3)UnsharadConcreateFlyweight:復合享元角色所代表的對象是不可以共享的,並且可以分解成為多個單純享元對象的組合。單純享元模式沒有此項,這也是兩者在結構上的區別。

(4)FlyweightFactoiy:享元工廠,負責管理享元對象池和創建享元對象。

(5)Client:維護對所有享元對象的引用,而且還需要存儲對應的外蘊狀態。

4.簡單實現

情景:過年買火車票的時候,我們需要查詢車票的情況,那麼如果每次查詢車票時都創建一個結果,那麼必然會大量的創建出許多重復的對象,頻繁的去銷毀他們,使得GC任務繁重。那麼這時我們可以使用享元模式,將這些對象緩存起來,查詢時優先使用緩存,沒有緩存在重新創建。

首先是Ticket接口(Flyweight):

public interface Ticket {

    public void showTicketInfo(String bunk);

}

TrainTicket具體實現類(ConcreateFlyweight):

//火車票
public class TrainTicket implements Ticket{

    public String from; // 始發地
    public String to; // 目的地
    public String bunk; //鋪位
    public int price; //價格

    public TrainTicket(String from, String to) {
        this.from = from;
        this.to = to;
    }

    @Override
    public void showTicketInfo(String bunk) {
        price = new Random().nextInt(300);
        System.out.println("購買 從 " + from + " 到 " + to + "的" + bunk + "火車票" + ", 價格:" + price);
    }

}

TicketFactory 管理查詢火車票(FlyweightFactoiy):

public class TicketFactory {
    static Map sTicketMap = new ConcurrentHashMap(); 

    public static Ticket getTicket(String from ,String to){
        String key = from + "-" + to;
        if(sTicketMap.containsKey(key)){
            System.out.println("使用緩存 ==> " + key);
            return sTicketMap.get(key);
        }else{
            System.out.println("創建對象 ==> " + key);
            Ticket ticket = new TrainTicket(from, to);
            sTicketMap.put(key, ticket);
            return ticket;
        }

    }
}

查詢:

final class Client {
    public static void main(String[] args) {
        Ticket ticket01 = TicketFactory.getTicket("北京", "青島");
        ticket01.showTicketInfo("上鋪");

        Ticket ticket02 = TicketFactory.getTicket("北京", "青島");
        ticket02.showTicketInfo("下鋪");

        Ticket ticket03 = TicketFactory.getTicket("北京", "西安");
        ticket03.showTicketInfo("坐票");
    }
}

結果

創建對象 ==> 北京-青島
購買 從 北京 到 青島的上鋪火車票, 價格:71
使用緩存 ==> 北京-青島
購買 從 北京 到 青島的下鋪火車票, 價格:32
創建對象 ==> 北京-西安
購買 從 北京 到 西安的坐票火車票, 價格:246

5.Android源碼中的實現

1.Message

因為Android是事件驅動的,因此如果通過new創建 Message 就會創建大量的 Message 對象,導致內存占用率高,頻繁GC等問題。那麼 Message 就采用了享元模式。

Message通過next成員變量保有對下一個Message的引用,最後一個可用Messagenext則為空。從而構成了一個Message鏈表Message Pool就通過該鏈表的表頭管理著所有閒置的Message,一個Message在使用完後可以通過recycle()方法進入Message Pool,並在需要時通過obtain靜態方法從Message Pool獲取。Message 承擔了享元模式中3個元素的職責,即是Flyweight抽象,又是ConcreateFlyweight角色,同時又承擔了FlyweightFactoiy管理對象池的職責。

所以使用Message推薦obtain(),不要去new了。

//1。使用new Message()  
//Message mess = new Message();  

//2。使用Message.obtain()  
Message mess = Message.obtain();  
mess.what = 1;  

//Message mess = mHandler.obtainMessage(1);  與上兩行的代碼一樣,可以參考源碼查看  
mHandler.sendMessage(mess);  

6.總結

1.優點

(1)大大減少應用程序創建的對象,降低程序內存的占用,增強程序的性能。

(2)使用享元模式,可以讓享元對象可以在不同的環境中被共享。

2.缺點

(1)使得系統更加復雜。為了使對象可以共享,需要將一些狀態外部化,這使得程序的邏輯復雜化。

(2)享元模式將需、享元對象的狀態外部化,而讀取外部狀態使得運行時間稍微變長。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved