1、意图
运用共享技术有效地支持大量细粒度的对象
2、动机
Flyweight模式描述了如何共享对象,使得可以细粒度地使用它们而无需高昂的代价。
3、适用性
Flyweight模式的有效性很大程度上取决于如何使用它以及在何处使用它。
-
一个应用程序使用了大量的对象;
-
完全由于使用了大量的对象,造成很大的存储开销;
-
对象的大多数状态都可变为外部状态;
-
如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组的对象;
-
应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
4、结构
下面的对象图说明了如何共享flyweight:
5、参与者
- Flyweight: 定义一个接口,通过这个接口Flyweight可以接受并作用于外部状态。
- ConcreteFlyweight:实现Flyweight接口,并增加内部状态。ConcreteFlyweight对象必须是可共享的。
- UnsharedConcreteflyweight:并非所有的Flyweight子类对象都需要被共享。flyweight接口使共享成为可能,但它并不强制共享。
- FlyweightFactory:
- 创建并管理Flyweight对象;
- 确保合理地共享Flyweight。当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或创建一个。 - Client:维持一个对Flyweight的引用;计算或存储一个(或多个)Flyweight对象的外部状态。
6、协作
- Flyweight执行是所需要的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象中,而外部状态则由Client对象存储或计算,当用户调用flyweight接口时,传递该状态。
- 用户不应直接对ConcreteFlyweight类进行实例化,而只能从FlyweightFactory对象得到ConcreteFlyweight对象,这可以保证对它们适当的进行共享。
7、效果
使用Flyweight模式时,传输、查找(计算)外部状态都会产生运行时的开销,然而空间上的节省抵消了这些开销。共享的flyweight越多,空间节省也就越大。节约量随着共享状态的增多而增大,当对象使用大量的内部和外部状态,并且外部状态时计算出来的而非存储的时候,节约量将达到最大。
所以,可用两种方法来节约存储:用共享来减少内部状态的消耗,用计算时间换取对外部状态的存储。
8、实现
- 识别外部状态 该模式的可用性在很大程度上取决于是否很容易识别外部状态并将它从对象中删除。如果不同种类的外部状态和共享前对象的数目一样的话,删除外部状态不会降低存储消耗。理想的情况是,外部状态可以由一个单独的对象结构计算得到,且该结构的存储要求非常小。
- 管理共享对象 用户不能直接实例化共享对象,而应通过FlyweightFactory对象查找感兴趣的Flyweight对象。
共享还意味着引用计数和垃圾回收机制,然而当共享对象量很小时,可以永久保存,不需要这两种操作。
9、相关模式
-
Flyweight模式通常和Composite模式结合起来,用共享叶节点的有向无环图实现一个逻辑上的层次结构。
-
通常,最好用Flyweight模式实现State和Strategy对象。