0%

设计模式——享元模式

运用共享技术来有效地支持大量细粒度对象的复用,通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。一般不变类都会使用享元模式。

享元模式与单例模式的区别:

  • 单例模式中一个类只能创建一个对象。
  • 享元模式中一个类可以创建多个对象,只不过可以采用工厂等方式共享同一个对象,并且可以控制对象创建或使用的数量。比如数据库连接池,不是单例模式示例,而是享元模式示例。

优点:极大减少内存中相似或相同对象数量,节约系统资源,提供系统性能。

缺点:需要关注内/外部状态,代码更加复杂、如果对象复用度低,则不适用与享元模式。

核心思想:如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝,而不必为每一次使用都创建新的对象。在享元模式中,由于需要构造和维护这些可以共享的对象,因此,常会出现一个工厂类,用于维护和创建对象。

享元模式的主要角色由享元工厂、抽象享元、具体享元类和主函数几部分组成。

  • 享元工厂:用于创建具体享元类,维护相同的享元对象。它保证相同的享元对象可以被系统共享。即,其内部使用了类似单例模式的方法,当请求对象已经存在时,直接返回对象,不存在时,在创建对象。享元工厂是享元模式的核心,它需要确保系统可以共享相同的对象。一般情况下,享元工厂会维护一个对象集合,当任何组件尝试获取享元类时,如果请求的享元类已经被创建,则直接返回已有的享元类:若没有,则创建一个新的享元对象,并将它加入到维护队列中。

  • 抽象享元:定义需要共享的对象业务接口。享元类被创建出来总是为了实现某些特定的业务逻辑,而抽象享元便定义这些逻辑的语义行为。

  • 具体享元类:实现抽象享元类的接口,完成某一具体逻辑。

  • 客户端:使用享元模式的组件,通过享元工厂取得享元对象。

享元模式经典的应用场景就是池技术了,String 常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式

Integer 类使用了享元模式,通过Integer.valueOf()这个静态工厂方法创建Integer实例,当传入的int范围在-128~`+127之间时,会直接返回缓存的Integer`实例(自动装箱时底层会使用 Integer.valueOf())。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public final class Integer extends Number implements Comparable<Integer> {

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

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) {
}
}
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() {}
}
}
-------本 文 结 束 感 谢 您 的 阅 读-------