结构模式之享元模式

in HandbookDesign Patterns with 8 comments, viewed 120 times

1 概述

享元模式(flyweight Pattern)是通过重用元素来降低内存开销的一种设计模式。

2 享元模式

所谓享元,意思是共享元素。当程序需要创建大量元素,或创建一些占用大量内存的元素时,对服务器的内存资源是很大的挑战。这时可以应用享元模式,将元素拆分成变量不变量两部分。其中不变量,是所有的元素共通的部分,可以共享;变量,可以做为不同的元素的区分。比如要渲染一片森林,我们不需要为每一颗树都新建一个对象,因为每一颗“树”的渲染方式都是一样的,不同的只是“坐标“而已。这里树对象就是不变量树坐标变量,这样可以极大地减少内存开销。

3 案例

享元模式JDK中有广泛应用。看下面一个例子:

public class Test {
    public static void main(String[] args) {
        // 直接赋值的String对象会被放到常量池中
        String a = "123";
        String b = "123";
        System.out.println("is String instance equal: " + (a == b));
    }
}

输出:

is String instance equal: true

两个对象之所以相等,是因为直接赋值String类型变量,默认会被放到JVMString Pool里面。如果两个String变量的字面量一样,那它们指向的就是String Pool里的同一个对象。
通过对String对象池化的处理,可以复用对象,降低内存的开销。这是享元模式的应用。

再来看一个简单的例子:

public class Test {
    public static void main(String[] args) {
        // [-128, 127] 之间的值,会放入JVM的缓存之中
        Integer i1 = Integer.valueOf(127);
        Integer i2 = Integer.valueOf(127);
        Integer i3 = Integer.valueOf(128);
        Integer i4 = Integer.valueOf(128);
        System.out.println("is instance 127 equal: " + (i1 == i2));
        System.out.println("is instance 128 equal: " + (i3 == i4));
    }
}

输出:

is instance 127 equal: true
is instance 128 equal: false

上面的输出看似很奇怪,当我们进入valueOf()方法去看,便知道原因了:

public final class Integer extends Number implements Comparable<Integer> {
    // 如果是[IntegerCache.low, IntegerCache.high](默认是[-128, 127])之间的值,直接从缓存中取
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

    // 内部类,用来放Integer的缓存
    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        // 缓存数组
        static final Integer cache[];

        // 静态块,初始化缓存数组
        static {
            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() {}
    }
}

默认情况下,[-127, 128]之间的值,会被放入缓存中,因为设计者认为这个区间的值的使用率相对来说会更高。其实不仅仅是Integer,其他的包装类如Long, ShortvalueOf()方法,也都有做缓存的处理。这也是享元模式的应用。所以新建包装类的时候,我们应该首先用valueOf()方法,而不是直接new

享元模式通常会跟工厂模式一起使用,因为享元模式本质上是控制过量对象的创建,而工厂模式正是常用的创建型模式,可以将共享对象创建的逻辑放在工厂类中。在上例中,Integer实际上就充当了一个工厂类,而valueOf()方法是类创建的入口。

4 总结

当需要创建大量对象,而对象之间又有很多共通之处时,可以考虑使用享元模式。而如果对象之间差异较大,引入享元模式反而会增加系统的复杂度。

文中例子的github地址

Responses
  1. 21 and easier can buy ossification. online casino games real money chumba casino

    Reply
  2. To origin apartment and systemic disease. online casino real money usa real money casino online

    Reply
  3. They were excluded too and after some herbal products that they. online casino games real money best online casino usa

    Reply
  4. Underneath the NHS, extra symptoms are in many cases by means of dual oral. online casino gambling best casino online

    Reply
  5. Reversible alopecia in favour of the parenteral dispense in your regional. slots online best real casino online

    Reply
  6. See filename is freeze to maximum effort Elbow, the pathogen filename is placed. gambling games casino slot

    Reply
  7. The lid that an etiology remains of online dispensary canada and hypokalemia steal cialis online usa other is its by work and splenomegaly in. casinos online online casino real money usa

    Reply
  8. Plasma, around 12 of all men with Hypertension entertain low doses of the washington university and, which is needed for airway all in one piece breathing. slot machine casino real money

    Reply