浅谈享元设计模式

概述

享元模式是一种结构型设计模式,它的意图是复用对象,从而节省内存,且前提是享元对象是不可变对象。之所以要求享元是不可变对象,是因为它会被多处代码共享使用,避免一处代码对享元进行了修改,影响到其他使用它的代码。

实际上,不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段)提取出来,设计成享元,让这些大量相似对象引用这些享元。

简单实现

享元模式的代码实现非常简单,主要是通过工厂模式,在工厂类中,通过一个 Map 或者 List 来缓存已经创建好的享元对象,以达到复用的目的。

具体可以参考Java中的 Integer 缓冲池。

享元模式的缺点

享元模式对GC并不友好,因为本身的设计要求,导致享元对象不会被GC掉。

因此,如果对象的生命周期很短,也不会被密集使用,利用享元模式反倒可能会浪费更多的内存。

具体应用

其他 Wrapper类也使用了这种设计模式

实际上,Java Integer类就用到了享元设计模式。 → 其中的[-128, 127]的常量池。

具体的,当我们使用 int/Integer 类型时,可能会用到自动拆箱/装箱机制。

Integer i1 = 10; 的底层就是自动装箱 → Integer i1 = Integer.valueOf(10);

为了节约内存,复用对象,Java对 valueOf() 方法用了享元模式进行了优化,如果值的范围在[-128, 127]之间,那么就会复用创建好的对象。 → 范围内对象的创建时机是 IntegerCache 类初始化时 → static代码块中

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

这其中的 IntegerCache 就相当于生成享元对象的工厂类。具体源码如下,可以简单看下:

/**
 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

参考:王争老师的极客时间专栏《设计模式之美》,质量巨高,强烈推荐!!!

你可能感兴趣的:(设计模式,设计模式)