美文网首页
设计模式-享元模式

设计模式-享元模式

作者: 小的橘子 | 来源:发表于2019-09-30 14:43 被阅读0次

    享元模式介绍

    享元模式(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() 方法

    相关文章

      网友评论

          本文标题:设计模式-享元模式

          本文链接:https://www.haomeiwen.com/subject/bxecpctx.html