1.享元模式介紹
? ? ? ? 享元模式(Flyweight Pattern)是對象池的一種實現(xiàn)。享元模式用來盡可能減少內(nèi)存使用量,適合用于可能存在大量重復對象的場景,來緩存可共享的對象,達到對象共享,避免創(chuàng)建過多對象的效果,這樣一來就可以提升性能,避免內(nèi)存移除等。
? ? ? ? 享元對象中的部分狀態(tài)是可以共享,可以共享的狀態(tài)成為內(nèi)部狀態(tài),內(nèi)部狀態(tài)不會隨著環(huán)境變化;不可共享的狀態(tài)稱之為外部狀態(tài),它們會隨著環(huán)境的改變而改變。在享元模式中會建立一個對象容器,在經(jīng)典的享元模式中該容器為一個Map,他的鍵是享元對象的內(nèi)部狀態(tài),它的值就是享元對象本身??蛻舳送ㄟ^這個內(nèi)部狀態(tài)從享元工廠中獲取享元對象,如果有緩存則使用緩存對象,否則創(chuàng)建一個享元對象并且存入容器中,這樣一來就避免了創(chuàng)建過多對象的問題。
2.享元模式定義
使用共享對象可有效地支持大量的細粒度的對象。
3享元模式的使用場景
1.系統(tǒng)中存在大量的相似對象。
2.細粒度的對象都具備較接近的外部狀態(tài),而且內(nèi)部狀態(tài)與環(huán)境無關,也就是說對象沒有特定身份。
3.需要緩沖池的場景。
4.UML類圖

5.角色介紹
1.Flyweight:享元對象抽象基類或接口。
2.ConcreteFlayweight:具體的享元對象。
3.FlyweightFactory:享元工廠,負責管理享元對象池和創(chuàng)建享元對象。
6.例子




例子分析
? ? ? ? 1.享元對象有抽象類或接口,然后對其進行實現(xiàn),再寫一個享元工廠,享元工廠負責管理享元對象池和創(chuàng)建享元對象。
? ? ? ? 2.車票是一個接口,有一個showTicketInfo的方法,火車票是其具體實現(xiàn)類,然后車票工廠是享元工廠類,里面有個Map,享元對象沒有就創(chuàng)建按并存入Map里,有就從Map里取出,例子里是把始發(fā)地和目的地作為Map的key值,把車票信息即享元對象作為Map的value值。始發(fā)地和目的地不會隨著環(huán)境變化所以作為內(nèi)部狀態(tài)即key,車票信息會隨時變化所以作為外部狀態(tài)即value。
7.Android源碼中的享元模式
? ??????Handler 消息機制中的 Message 消息池就是使用享元模式復用了 Message 對象。使用 Message 時一般是用 Message.obtain 來獲取消息。如果使用 new Message() 會構(gòu)造大量的 Message 對象。Message相當于承擔了享元模式中3個元素的職責,既是Flyweight抽象,又是ConcreteFlyweight角色,同時又承擔了FlyweightFactory管理對象池的職責。如果通過new創(chuàng)建Message就會創(chuàng)建大量重復的Message對象,導致內(nèi)存占用率高,頻繁GC等問題,通過享元模式創(chuàng)建一個大小為50的消息池,避免了上述問題的產(chǎn)生。Message的享元模式并不是經(jīng)典的實現(xiàn)方式,它沒有內(nèi)部,外部狀態(tài),集各個職責于一身,甚至更像一個對象池。
8.總結(jié)
? ? ? ? 享元模式可以大大減少應用程序創(chuàng)建的對象,降低程序內(nèi)存的占用,增強程序的性能,但同時也提高了系統(tǒng)的復雜性,需要分離出外部狀態(tài)和內(nèi)部狀態(tài),而且外部狀態(tài)具有固化特性,不應該隨內(nèi)部狀態(tài)而改變,否則導致系統(tǒng)的邏輯混亂。
????????享元模式的優(yōu)點在于它大幅度地降低內(nèi)存中對象數(shù)量。但是,它做到這樣的代價是很高的。享元模式使得系統(tǒng)更加復雜,為了使對象可以共享,需要將一些狀態(tài)外化,使得程序的邏輯復雜化。享元模式將享元對象的狀態(tài)外部化,而讀取外部狀態(tài)使得運行時間稍微變長。
PS:讀《Android源碼設計模式解析與實戰(zhàn)》中的享元模式之后的一些筆記與感悟