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

來源:互聯網
上載者:User

標籤:佔用   不同的   表頭   interface   sdn   ret   main   img   ticket   

第二十二章、享元模式

享元模式是結構型設計模式之中的一個。是對對象池的一種實現。就像它的名字一樣,共用對象。避免反覆的建立。

我們經常使用的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<String, Ticket> sTicketMap = new ConcurrentHashMap<String, Ticket>();     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)享元模式將需、享元對象的狀態外部化,而讀取外部狀態使得執行時間略微變長。

7.參考

1. 深入淺出享元模式

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.