摘要
享元模式(Flyweight Pattern): 利用共享的方式来支持大量细粒度的对象,这些对象一部分内部状态是相同的。 它让某个类的一个实例能用来提供许多"虚拟实例"。
一、享元设计模式意图
享元模式 (Flyweight) 是一种结构型设计模式,它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。
二、享元设计模式场景
- 仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式。
三、享元设计模式类图
- 享元模式只是一种优化。 在应用该模式之前, 你要确定程序中存在与大量类似对象同时占用内存相关的内存消耗问题, 并且确保该问题无法使用其他更好的方式来解决。
- 享元 (Flyweight) 类包含原始对象中部分能在多个对象中共享的状态。 同一享元对象可在许多不同情景中使用。 享元中存储的状态被称为 “内在状态”。 传递给享元方法的状态被称为 “外在状态”。
- 情景 (Context) 类包含原始对象中各不相同的外在状态。 情景与享元对象组合在一起就能表示原始对象的全部状态。
- 通常情况下, 原始对象的行为会保留在享元类中。 因此调用享元方法必须提供部分外在状态作为参数。 但你也可将行为移动到情景类中, 然后将连入的享元作为单纯的数据对象。
- 客户端 (Client) 负责计算或存储享元的外在状态。 在客户端看来, 享元是一种可在运行时进行配置的模板对象, 具体的配置方式为向其方法中传入一些情景数据参数。
- 享元工厂 (Flyweight Factory) 会对已有享元的缓存池进行管理。 有了工厂后, 客户端就无需直接创建享元, 它们只需调用工厂并向其传递目标享元的一些内在状态即可。 工厂会根据参数在之前已创建的享元中进行查找, 如果找到满足条件的享元就将其返回; 如果没有找到就根据参数新建享元。
四、享元设计模式实现
Flyweight : 它是所有具体享元类的超类或接口,通过这个接口,Flyweight 可以接受并作用于外部状态。
abstract class Flyweight {
public abstract void operation(int extrinsicstates);
}
ConcreteFlyweight : 是继承 Flyweight 超类或实现 Flyweight 接口,并为内部状态增加存储空间。
class ConcreteFlyweight extends Flyweight {
@Override
public void operation(int extrinsicstates) {
System.out.println("共享的Flyweight : " + extrinsicstates);
}
}
UnsharedConcreteFlyweight : 指那些不需要共享的 Flyweight 子类,因为 Flyweight 接口共享成为可能,但它并不强制共享。
class UnsharedConcreteFlyweight extends Flyweight {
@Override
public void operation(int extrinsicstates) {
System.out.println("不共享的Flyweight : " + extrinsicstates);
}
}
FlywightFactory :是一个享元工厂,用来创建并管理 Flyweight 对象。它主要是用来确保合理地共享 Flyweight ,当用户请求一个 Flyweight 时, FlyweightFactory 对象提供一个已创建的实例或创建一个(如果对象不存在的话)。
class FlywightFactory {
private Hashtable<String, Flyweight> flyweights = new Hashtable<String, Flyweight>();
public FlywightFactory() {
flyweights.put("X", new ConcreteFlyweight());
flyweights.put("Y", new ConcreteFlyweight());
flyweights.put("Z", new ConcreteFlyweight());
}
public Flyweight getFlyweight(String key) {
return ((Flyweight)flyweights.get(key));
}
}
public class FlyweightPattern {
public static void main(String[] args) {
int extrinsicstates = 1;
FlywightFactory factory = new FlywightFactory();
Flyweight fx = factory.getFlyweight("X");
fx.operation(extrinsicstates);
Flyweight fy = factory.getFlyweight("Y");
fy.operation(++extrinsicstates);
Flyweight fz = factory.getFlyweight("Z");
fz.operation(++extrinsicstates);
Flyweight uf = new UnsharedConcreteFlyweight();
uf.operation(++extrinsicstates);
}
}
======================================================
共享的Flyweight : 1
共享的Flyweight : 2
共享的Flyweight : 3
不共享的Flyweight : 4
五、享元设计模式总结
你可以使用享元模式 (opens new window)实现组合模式 (opens new window)树的共享叶节点以节省内存。
- 享元 (opens new window)展示了如何生成大量的小型对象, 外观模式 (opens new window)则展示了如何用一个对象来代表整个子系统。
- 如果你能将对象的所有共享状态简化为一个享元对象, 那么享元 (opens new window)就和单例模式 (opens new window)类似了。 但这两个模式有两个根本性的不同。
- 只会有一个单例实体, 但是享元类可以有多个实体, 各实体的内在状态也可以不同。
- 单例对象可以是可变的。 享元对象是不可变的。
六、享元设计模式开源示例
Java 利用缓存来加速大量小对象的访问时间。
- java.lang.Integer#valueOf(int)
- java.lang.Boolean#valueOf(boolean)
- java.lang.Byte#valueOf(byte)
- java.lang.Character#valueOf(char)