讓我們先來復習下java中String類型的特性:String類型的對象一旦被創造就不可改變;當兩個String對象所包含的內容相同的時候,JVM只創建一個String對象對應這兩個不同的對象引用。讓我們來證實下著兩個特性吧(如果你已經了解,請跳過直接閱讀第二部分)。
先來驗證下第二個特性:
public class TestPattern {
public static void main(String[] args){
String n = "I Love Java";
String m = "I Love Java";
System.out.println(n==m);
}
}
這段代碼會告訴你n==m是true,這就說明了在JVM中n和m兩個引用了同一個String對象(如果你還分不清== 和 equals的區別的話,請先確認)。
那么接著驗證下第一個特性:
在系統輸出之前加入一行代碼“m = m + "hehe";”,這時候n==m結果為false,為什么剛才兩個還是引用相同的對象,現在就不是了呢?原因就是在執行后添加語句時,m指向了一個新創建的String對象,而不是修改引用的對象。
呵呵,說著說著就差點跑了題,并不是每個String的特性都跟我們今天的主題有關的。
String類型的設計避免了在創建N多的String對象時產生的不必要的資源損耗,可以說是享元模式應用的范例,那么讓我們帶著對享元的一點模糊的認識開始,來看看怎么在自己的程序中正確的使用享元模式!
享元模式:運用共享技術有效地支持大量大量細粒度的對象.
享元模式英文稱為“Flyweight Pattern”,我非常感謝將Flyweight Pattern翻譯成享元模式的那位強人,因為這個詞將這個模式使用的方式明白得表示了出來;如果翻譯成為羽量級模式或者蠅量級模式等等,雖然可以含蓄的表現出使用此模式達到的目的,但是還是沒有抓住此模式的關鍵。
享元模式的定義為:采用一個共享來避免大量擁有相同內容對象的開銷。這種開銷中最常見、直觀的就是內存的損耗。享元模式以共享的方式高效的支持大量的細粒度對象。
在名字和定義中都體現出了共享這一個核心概念,那么怎么來實現共享呢?要知道每個事物都是不同的,但是又有一定的共性,如果只有完全相同的事物才能共享,那么享元模式可以說就是不可行的;因此我們應該盡量將事物的共性共享,而又保留它的個性。為了做到這點,享元模式中區分了內蘊狀態和外蘊狀態。內蘊狀態就是共性,外蘊狀態就是個性了。
注:共享的對象必須是不可變的,不然一變則全變(如果有這種需求除外)。
內蘊狀態存儲在享元內部,不會隨環境的改變而有所不同,是可以共享的;外蘊狀態是不可以共享的,它隨環境的改變而改變的,因此外蘊狀態是由客戶端來保持(因為環境的變化是由客戶端引起的)。在每個具體的環境下,客戶端將外蘊狀態傳遞給享元,從而創建不同的對象出來。至于怎樣來維護客戶端保持的外蘊狀態和享元內部保持的內蘊狀態的對應關系,你先不用擔心這個問題,我們后面會涉及到的。
我們引用《Java與模式》中的分類,將享元模式分為:單純享元模式和復合享元模式。在下一個小節里面我們將詳細的講解這兩種享元模式。
享元模式的組成部份:
1.享元接口 定義了享元
2.具體享遠 實現享元接口
3.享元工廠 負責管理和創建享元對象,一般包含一個Map, 保存享元對象,使用都請求享元時,先到map里找是否有這個享元,如果有,返回,沒有就創建該享元.機制有點像對時所做的簡單的緩存.
各部份的組成關系:

使用優缺點
享元模式優點就在于它能夠大幅度的降低內存中對象的數量;而為了做到這一步也帶來了它的缺點:它使得系統邏輯復雜化,而且在一定程度上外蘊狀態影響了系統的速度。
所以一定要切記使用享元模式的條件:
1) 系統中有大量的對象,他們使系統的效率降低。
2) 這些對象的狀態可以分離出所需要的內外兩部分。
外蘊狀態和內蘊狀態的劃分以及兩者關系的對應也是非常值得重視的。只有將內外劃分妥當才能使內蘊狀態發揮它應有的作用;如果劃分失誤,在最糟糕的情況下系統中的對象是一個也不會減少的!兩者的對應關系的維護和查找也是要花費一定的空間(當然這個比起不使用共享對象要小得多)和時間的,可以說享元模式就是使用時間來換取空間的。在Gof的書中是使用了B樹來進行對應關系查找優化。
總結
也許你要長嘆一聲:這個享元模式未必太復雜了吧!這點是不得不承認的,也許由于它的復雜,實際應用也不是很多,這是我們更加無法看清他的真面目了。不過享元模式并不是雞肋,它的精髓——共享是對我們系統優化非常有好處的,而且這種思想已經別越來越多的應用,這應該就算是享元模式的應用了吧。如果你已經領會到了享元模式的精髓,那么也就是掌握了享元模式了!
匆匆學完了享元模式,不知道理解上有沒有紕漏,希望大家能指正出來,一起共同進步!其實我一直想使用一個實際系統中或者實踐中的例子來講解享元模式,可是畢竟自己的工作經驗太少了!!于是想在網上找一些靈感來,可是狂搜一陣子也沒有發現什么,于是就又落俗套的使用了一個比喻的例子。如果您對此深有體會的話,還煩請不吝賜教!!