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

享元模式介紹

享元模式(Flyweight Pattern)是結(jié)構(gòu)型設(shè)計(jì)模式的一種。其實(shí)對(duì)象池的一種實(shí)現(xiàn)方式,通過(guò)緩存可共享的對(duì)象,來(lái)減少對(duì)象的創(chuàng)建寒砖,可以降低程序內(nèi)存占用,提高程序性能嫉拐。

享元模式定義

使用共享對(duì)象有效的支持大量細(xì)粒度的對(duì)象

享元模式的使用場(chǎng)景

  1. 系統(tǒng)中存在大量的相似對(duì)象哩都。
  2. 細(xì)粒度的對(duì)象都具備接近的外部狀態(tài),而且內(nèi)部狀態(tài)與環(huán)境無(wú)關(guān)婉徘。
  3. 需要緩沖池的場(chǎng)景漠嵌。

內(nèi)部狀態(tài):對(duì)象中可以共享的狀態(tài),其不會(huì)隨著環(huán)境變化盖呼。
外部狀態(tài):對(duì)象中不可以共享的狀態(tài)儒鹿,它們會(huì)隨著環(huán)境的改變而變化。

享元模式的 UML 類圖


角色介紹:

  • Flyweight:享元對(duì)象抽象類几晤。
  • ConcreteFlyweight:具體享元對(duì)象约炎。
  • FlyweightFactory:享元工廠,負(fù)責(zé)管理享元對(duì)象池和創(chuàng)建享元對(duì)象蟹瘾。

享元模式的簡(jiǎn)單實(shí)現(xiàn)

這里某東出售手機(jī)為例圾浅,每個(gè)用戶選擇手機(jī)后都生成手機(jī)商品對(duì)象顯然耗費(fèi)很多資源,甚至造成 OOM憾朴,我們就可以采用享元模式優(yōu)化狸捕。

抽象享元角色

抽象享元角色是一個(gè)商品接口,它定義了showGoodsPrice方法用來(lái)展示商品的價(jià)格:

public interface IPrice {
    public void showGoodsPrice(String version);
}

具體享元角色

public class Phone implements IPrice {
    public String name;
    public String version;
    public int price;

    public Phone(String name) {
        this.name = name;
    }

    @Override
    public void showGoodsPrice(String version) {
        this.version = version;
        price = queryPrice(version);
        System.out.println("手機(jī) " + name + " 存儲(chǔ)版本為 " + version + "众雷,售價(jià)為:" + price);
    }

    private int queryPrice(String version) {
        switch (version) {
            case "128G":
                return 5000;
            case "256G":
                return 6000;
        }
        return 99999;
    }
}

其中 name 屬于內(nèi)部狀態(tài)灸拍,version 和 price 屬于外部狀態(tài)。showGoodsPrice方法根據(jù)手機(jī)存儲(chǔ) version 的不同會(huì)打印出不同的價(jià)格砾省。

享元工廠

public class PhoneFactory {
    private static Map<String, Phone> sPhoneMap = new HashMap<>();

    public static Phone getPhone(String name) {
        Phone ret = null;
        if (sPhoneMap.containsKey(name)) {
            System.out.println("使用緩存,key 為" + name);
            ret = sPhoneMap.get(name);
        } else {
            System.out.println("創(chuàng)建對(duì)象,key 為" + name);
            ret = new Phone(name);
            sPhoneMap.put(name, ret);
        }
        return ret;
    }
}

享元工廠PhoneFactory 用來(lái)創(chuàng)建 Phone 對(duì)象鸡岗。通過(guò)Map容器來(lái)存儲(chǔ) Phone 對(duì)象,將內(nèi)部狀態(tài) name 作為Map的key编兄,以便標(biāo)識(shí) Phone 對(duì)象纤房。如果Map容器中包含此key,則使用Map容器中存儲(chǔ)的 Phone 對(duì)象翻诉,否則就新創(chuàng)建 Phone 對(duì)象炮姨,并放入Map容器中。

客戶端調(diào)用

public class Client {
    public static void main(String[] args) {
        Phone phone1 = PhoneFactory.getPhone("HUAWEI mate30");
        phone1.showGoodsPrice("128G");
        Phone phone2 = PhoneFactory.getPhone("HUAWEI mate30");
        phone2.showGoodsPrice("256G");
    }
}

輸出結(jié)果:

創(chuàng)建對(duì)象,key 為HUAWEI mate30
手機(jī) HUAWEI mate30 存儲(chǔ)版本為 128G碰煌,售價(jià)為:5000
使用緩存,key 為HUAWEI mate30
手機(jī) HUAWEI mate30 存儲(chǔ)版本為 256G舒岸,售價(jià)為:6000

從輸出結(jié)果可以看到,只有第一次查詢手機(jī)創(chuàng)建了一次對(duì)象芦圾,后續(xù)的查詢都使用的是對(duì)象池中的對(duì)象蛾派。該例子中內(nèi)存狀態(tài)就是手機(jī)名稱,在查詢HUAWEI mate30 時(shí)內(nèi)部狀態(tài)不會(huì)發(fā)生變化;外部狀態(tài)就是存儲(chǔ)版本和價(jià)格洪乍,價(jià)格會(huì)隨著存儲(chǔ)版本不同而變化眯杏。通過(guò)緩存較少了內(nèi)存占用,降低了gc 回收的次數(shù)壳澳,從而性能大大提高岂贩。

總結(jié)

享元模式優(yōu)點(diǎn)
1.大大減少對(duì)象的創(chuàng)建,降低系統(tǒng)的內(nèi)存巷波,減少 GC 萎津,提高性能。
享元模式缺點(diǎn)
1.提高了系統(tǒng)的復(fù)雜度抹镊,需要分離出外部狀態(tài)和內(nèi)部狀態(tài)锉屈,當(dāng)然為了設(shè)備性能,這點(diǎn)必須做的垮耳。

Android 源碼中的享元模式

見(jiàn)Android 消息機(jī)制 Message 中 obtain() 和 recycle() 方法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颈渊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子终佛,更是在濱河造成了極大的恐慌儡炼,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件查蓉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡榜贴,警方通過(guò)查閱死者的電腦和手機(jī)豌研,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)唬党,“玉大人鹃共,你說(shuō)我怎么就攤上這事∈还埃” “怎么了霜浴?”我有些...
    開(kāi)封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蓝纲。 經(jīng)常有香客問(wèn)我阴孟,道長(zhǎng),這世上最難降的妖魔是什么税迷? 我笑而不...
    開(kāi)封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任永丝,我火速辦了婚禮,結(jié)果婚禮上箭养,老公的妹妹穿的比我還像新娘慕嚷。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布喝检。 她就那樣靜靜地躺著嗅辣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挠说。 梳的紋絲不亂的頭發(fā)上澡谭,一...
    開(kāi)封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音纺涤,去河邊找鬼译暂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛撩炊,可吹牛的內(nèi)容都是我干的外永。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼拧咳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伯顶!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起骆膝,我...
    開(kāi)封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤祭衩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后阅签,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體掐暮,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年政钟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了路克。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡养交,死狀恐怖精算,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碎连,我是刑警寧澤灰羽,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站鱼辙,受9級(jí)特大地震影響廉嚼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜倒戏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一前鹅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧峭梳,春花似錦舰绘、人聲如沸蹂喻。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)口四。三九已至,卻和暖如春秦陋,著一層夾襖步出監(jiān)牢的瞬間蔓彩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工驳概, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赤嚼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓顺又,卻偏偏與公主長(zhǎng)得像更卒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子稚照,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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