设计模式-享元模式

享元模式介绍

享元模式(Flyweight Pattern)是结构型设计模式的一种。其实对象池的一种实现方式,通过缓存可共享的对象,来减少对象的创建,可以降低程序内存占用,提高程序性能。

享元模式定义

使用共享对象有效的支持大量细粒度的对象

享元模式的使用场景

  1. 系统中存在大量的相似对象。
  2. 细粒度的对象都具备接近的外部状态,而且内部状态与环境无关。
  3. 需要缓冲池的场景。

内部状态:对象中可以共享的状态,其不会随着环境变化。
外部状态:对象中不可以共享的状态,它们会随着环境的改变而变化。

享元模式的 UML 类图


角色介绍:

  • Flyweight:享元对象抽象类。
  • ConcreteFlyweight:具体享元对象。
  • FlyweightFactory:享元工厂,负责管理享元对象池和创建享元对象。

享元模式的简单实现

这里某东出售手机为例,每个用户选择手机后都生成手机商品对象显然耗费很多资源,甚至造成 OOM,我们就可以采用享元模式优化。

抽象享元角色

抽象享元角色是一个商品接口,它定义了showGoodsPrice方法用来展示商品的价格:

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("手机 " + name + " 存储版本为 " + version + ",售价为:" + price);
    }

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

其中 name 属于内部状态,version 和 price 属于外部状态。showGoodsPrice方法根据手机存储 version 的不同会打印出不同的价格。

享元工厂

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("创建对象,key 为" + name);
            ret = new Phone(name);
            sPhoneMap.put(name, ret);
        }
        return ret;
    }
}

享元工厂PhoneFactory 用来创建 Phone 对象。通过Map容器来存储 Phone 对象,将内部状态 name 作为Map的key,以便标识 Phone 对象。如果Map容器中包含此key,则使用Map容器中存储的 Phone 对象,否则就新创建 Phone 对象,并放入Map容器中。

客户端调用

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");
    }
}

输出结果:

创建对象,key 为HUAWEI mate30
手机 HUAWEI mate30 存储版本为 128G,售价为:5000
使用缓存,key 为HUAWEI mate30
手机 HUAWEI mate30 存储版本为 256G,售价为:6000

从输出结果可以看到,只有第一次查询手机创建了一次对象,后续的查询都使用的是对象池中的对象。该例子中内存状态就是手机名称,在查询HUAWEI mate30 时内部状态不会发生变化;外部状态就是存储版本和价格,价格会随着存储版本不同而变化。通过缓存较少了内存占用,降低了gc 回收的次数,从而性能大大提高。

总结

享元模式优点
1.大大减少对象的创建,降低系统的内存,减少 GC ,提高性能。
享元模式缺点
1.提高了系统的复杂度,需要分离出外部状态和内部状态,当然为了设备性能,这点必须做的。

Android 源码中的享元模式

Android 消息机制 Message 中 obtain() 和 recycle() 方法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容