設(shè)計(jì)模式-享元模式

享元模式(Flyweight Pattern):運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度對(duì)象的復(fù)用。系統(tǒng)只使用少量的對(duì)象,而這些對(duì)象都很相似,狀態(tài)變化很小龙宏,可以實(shí)現(xiàn)對(duì)象的多次復(fù)用。由于享元模式要求能夠共享的對(duì)象必須是細(xì)粒度對(duì)象伤疙,因此它又稱為輕量級(jí)模式银酗,它是一種對(duì)象結(jié)構(gòu)型模式。

享元模式從字面上翻譯是“蠅量級(jí)模式”徒像,其實(shí)并不太好理解黍特。這個(gè)模式的作用就是在一個(gè)系統(tǒng)當(dāng)中有很多很多的對(duì)象,而這些對(duì)象很相似锯蛀,有細(xì)微地方不同灭衷,單數(shù)數(shù)量太大,影響系統(tǒng)性能旁涤,為了避免系統(tǒng)中出現(xiàn)大量相同或相似的對(duì)象翔曲,同時(shí)又不影響客戶端程序通過(guò)面向?qū)ο蟮姆绞綄?duì)這些對(duì)象進(jìn)行操作,享元模式橫空出世拭抬。

好比一個(gè)系統(tǒng)里面的字符,有非常之多侵蒙,每個(gè)字符在顯示的時(shí)候有的顏色不一樣造虎,有的大小不一樣,有的字體不一樣纷闺,享元模式通過(guò)共享技術(shù)實(shí)現(xiàn)相同或相似對(duì)象的重用算凿,在邏輯上每一個(gè)出現(xiàn)的字符都有一個(gè)對(duì)象與之對(duì)應(yīng),然而在物理上它們卻共享同一個(gè)享元對(duì)象犁功,這個(gè)對(duì)象可以出現(xiàn)在一個(gè)字符串的不同地方氓轰,相同的字符對(duì)象都指向同一個(gè)實(shí)例。而享元模式里面一個(gè)重要的地方是享元池浸卦,里面裝滿了各種享元對(duì)象署鸡。這里可以看出享元模式的“享”是共享,“元”代表公共對(duì)象的最原始的狀態(tài)限嫌。

先來(lái)看下享元模式的類圖:

  • Flyweight(抽象享元類):通常是一個(gè)接口或抽象類靴庆,在抽象享元類中聲明了具體享元類公共的方法,這些方法可以向外界提供享元對(duì)象的內(nèi)部數(shù)據(jù)(內(nèi)部狀態(tài))怒医,同時(shí)也可以通過(guò)這些方法來(lái)設(shè)置外部數(shù)據(jù)(外部狀態(tài))炉抒。
  • ConcreteFlyweight(具體享元類):它實(shí)現(xiàn)了抽象享元類,其實(shí)例稱為享元對(duì)象稚叹;在具體享元類中為內(nèi)部狀態(tài)提供了存儲(chǔ)空間焰薄。通常我們可以結(jié)合單例模式來(lái)設(shè)計(jì)具體享元類拿诸,為每一個(gè)具體享元類提供唯一的享元對(duì)象。
  • UnsharedConcreteFlyweight(非共享具體享元類):并不是所有的抽象享元類的子類都需要被共享塞茅,不能被共享的子類可設(shè)計(jì)為非共享具體享元類亩码;當(dāng)需要一個(gè)非共享具體享元類的對(duì)象時(shí)可以直接通過(guò)實(shí)例化創(chuàng)建。
  • FlyweightFactory(享元工廠類):享元工廠類用于創(chuàng)建并管理享元對(duì)象凡桥,它針對(duì)抽象享元類編程蟀伸,將各種類型的具體享元對(duì)象存儲(chǔ)在一個(gè)享元池中,享元池一般設(shè)計(jì)為一個(gè)存儲(chǔ)“鍵值對(duì)”的集合(也可以是其他類型的集合)缅刽,可以結(jié)合工廠模式進(jìn)行設(shè)計(jì)啊掏;當(dāng)用戶請(qǐng)求一個(gè)具體享元對(duì)象時(shí),享元工廠提供一個(gè)存儲(chǔ)在享元池中已創(chuàng)建的實(shí)例或者創(chuàng)建一個(gè)新的實(shí)例(如果不存在的話)衰猛,返回新創(chuàng)建的實(shí)例并將其存儲(chǔ)在享元池中迟蜜。

代碼實(shí)現(xiàn)下:
享元模式的抽象接口

public abstract class Flyweight {
    public abstract void operation(String state);
}

具體的享元類

public class ConcreteFlyweight extends Flyweight{

    private Character intrinsicState=null;
    
    //構(gòu)造函數(shù),設(shè)置內(nèi)部狀態(tài)
    public ConcreteFlyweight(Character intrinsicState) {
        this.intrinsicState=intrinsicState;
    }
    
    //外部狀態(tài)作為參數(shù)進(jìn)入方法
    @Override
    public void operation(String extrinsicState) {
        System.out.println("內(nèi)部狀態(tài)是:"+intrinsicState);
        System.out.println("外部狀態(tài)是:"+ extrinsicState);
    }

}

不需要共享的情況啡省,有時(shí)候就是需要在內(nèi)存里面新增一個(gè)

public class UnsharedConcreteFlyweight extends Flyweight{

    @Override
    public void operation(String extrinsicstate) {
        System.out.println("不共享的具體狀態(tài):"+extrinsicstate);
    }
}

接下來(lái)是享元模式的工廠娜睛,負(fù)責(zé)整合這些“元”,由一個(gè) Hash 表進(jìn)行管理,在構(gòu)造的時(shí)候沒(méi)有把不共享的“元”增加進(jìn)去卦睹,當(dāng)然也可以進(jìn)行判斷畦戒。

public class FlyweightFactory {

    private HashMap<String,Flyweight> characters=new HashMap<String,Flyweight>();
    public FlyweightFactory() {
        characters.put("A", new ConcreteFlyweight('a'));
        characters.put("B", new ConcreteFlyweight('b'));
        characters.put("C", new ConcreteFlyweight('c'));
    }
    
    public Flyweight getFlyweight(String key){
        return characters.get(key);
    }
    
}

Client 端將通過(guò)工廠從里面獲取,工廠一般可以做成單例结序,確保系統(tǒng)范圍只有一個(gè)享元工廠障斋。

public class Client {

    public static void main(String[] args) {
        FlyweightFactory factory=new FlyweightFactory();
        Flyweight a1=factory.getFlyweight("A");
        a1.operation("StateA1");
        
        Flyweight a2=factory.getFlyweight("A");
        a2.operation("StateA2");
        
        Flyweight b=factory.getFlyweight("B");
        b.operation("StateB");

    }

}

看下結(jié)果:

內(nèi)部狀態(tài)是:a
外部狀態(tài)是:StateA1
內(nèi)部狀態(tài)是:a
外部狀態(tài)是:StateA2
內(nèi)部狀態(tài)是:b
外部狀態(tài)是:StateB

擴(kuò)展:有的時(shí)候需要把幾個(gè) Flyweight 組合為一個(gè),這就出現(xiàn)了具體復(fù)合享元角色徐鹤,他是有一些單個(gè)的享元角色組合而成垃环,提供一個(gè)集合進(jìn)行管理,當(dāng)然也繼承抽象的享元角色返敬,也有 operation()方法遂庄,這個(gè)方法的唯一參數(shù)代表復(fù)合對(duì)象的外部狀態(tài),而且這個(gè)外部狀態(tài)和內(nèi)部包括的小享元的外部狀態(tài)一致劲赠,內(nèi)部狀態(tài)不一定一樣涛目。由于內(nèi)部狀態(tài)會(huì)改變,所以也是不能共享的凛澎。

優(yōu)點(diǎn)和缺點(diǎn)

享元模式的主要優(yōu)點(diǎn)如下:
(1) 可以極大減少內(nèi)存中對(duì)象的數(shù)量泌绣,使得相同或相似對(duì)象在內(nèi)存中只保存一份,從而可以節(jié)約系統(tǒng)資源预厌,提高系統(tǒng)性能阿迈。
(2) 享元模式的外部狀態(tài)相對(duì)獨(dú)立,而且不會(huì)影響其內(nèi)部狀態(tài)轧叽,從而使得享元對(duì)象可以在不同的環(huán)境中被共享苗沧。

享元模式的主要缺點(diǎn)如下:
(1) 享元模式使得系統(tǒng)變得復(fù)雜刊棕,需要分離出內(nèi)部狀態(tài)和外部狀態(tài),這使得程序的邏輯復(fù)雜化待逞。
(2) 為了使對(duì)象可以共享甥角,享元模式需要將享元對(duì)象的部分狀態(tài)外部化,而讀取外部狀態(tài)將使得運(yùn)行時(shí)間變長(zhǎng)识樱。

該模式使用頻率不高嗤无,場(chǎng)合不多,在以下情況下可以考慮使用享元模式:
(1) 一個(gè)系統(tǒng)有大量相同或者相似的對(duì)象怜庸,造成內(nèi)存的大量耗費(fèi)当犯。
(2) 對(duì)象的大部分狀態(tài)都可以外部化,可以將這些外部狀態(tài)傳入對(duì)象中割疾。
(3) 在使用享元模式時(shí)需要維護(hù)一個(gè)存儲(chǔ)享元對(duì)象的享元池嚎卫,而這需要耗費(fèi)一定的系統(tǒng)資源,因此宏榕,應(yīng)當(dāng)在需要多次重復(fù)使用享元對(duì)象時(shí)才值得使用享元模式拓诸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市麻昼,隨后出現(xiàn)的幾起案子奠支,更是在濱河造成了極大的恐慌,老刑警劉巖抚芦,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件倍谜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡燕垃,警方通過(guò)查閱死者的電腦和手機(jī)枢劝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門井联,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)卜壕,“玉大人,你說(shuō)我怎么就攤上這事烙常≈嵘樱” “怎么了蚕脏?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵驼鞭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我译隘,道長(zhǎng),這世上最難降的妖魔是什么题篷? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任厅目,我火速辦了婚禮损敷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘渔欢。我一直安慰自己瘟忱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布垫挨。 她就那樣靜靜地躺著触菜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哲泊。 梳的紋絲不亂的頭發(fā)上催蝗,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天丙号,我揣著相機(jī)與錄音,去河邊找鬼喳魏。 笑死怀薛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的创倔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼念搬!你這毒婦竟也來(lái)了朗徊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤有缆,失蹤者是張志新(化名)和其女友劉穎棚壁,沒(méi)想到半個(gè)月后栈虚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡曼验,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年鬓照,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了孤紧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翼抠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出活喊,到底是詐尸還是另有隱情量愧,我是刑警寧澤帅矗,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布浑此,位于F島的核電站滞详,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蒲犬。R本人自食惡果不足惜原叮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一奋隶、第九天 我趴在偏房一處隱蔽的房頂上張望悦荒。 院中可真熱鬧逾冬,春花似錦、人聲如沸身腻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至媒佣,卻和暖如春默伍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背炼蹦。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工掐隐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人指攒。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓膝擂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親隙弛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子架馋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 目錄 本文的結(jié)構(gòu)如下: 引言 什么是享元模式 模式的結(jié)構(gòu) 典型代碼 代碼示例 單純享元模式和復(fù)合享元模式 模式擴(kuò)展...
    w1992wishes閱讀 1,436評(píng)論 0 6
  • 定義 Flyweight在拳擊比賽中指最輕量級(jí),即“蠅量級(jí)”或“雨量級(jí)”全闷。這里選擇使用“享元模式”的意譯叉寂,是因?yàn)檫@...
    步積閱讀 1,615評(píng)論 0 2
  • 享元模式(Flyweight) 在面向?qū)ο蟪绦蛟O(shè)計(jì)過(guò)程中,有時(shí)會(huì)面臨要?jiǎng)?chuàng)建大量相同或相似對(duì)象實(shí)例的問(wèn)題总珠。創(chuàng)建那么多...
    Acton_zhang閱讀 218評(píng)論 1 1
  • 場(chǎng)景 網(wǎng)絡(luò)聯(lián)機(jī)下棋的時(shí)候屏鳍,一臺(tái)服務(wù)器連接了多個(gè)客戶端(玩家),如果我們每個(gè)棋子都要?jiǎng)?chuàng)建對(duì)象局服,那一盤棋可能就有上百個(gè)...
    皆為序幕_閱讀 196評(píng)論 0 0
  • 《9+幾》課堂片段 第一個(gè)環(huán)節(jié)钓瞭,9+2。孩子們借助小棒淫奔,自己動(dòng)手?jǐn)[一擺山涡,擺出一個(gè)9,再擺出一個(gè)2唆迁,有的孩子用數(shù)一數(shù)...
    陽(yáng)光綠閱讀 245評(píng)論 0 0