Flyweight模式
Flyweight模式的用意
??? Flyweight模式是对象的结构模式。Flyweight模式以共享的方式高效的支持大量的细粒度对象。
??? Flyweight对象能够做到共享的关键是区分内部状态(Internal State)和外部状态(External State)。
??? 一个内部状态是存储在Flyweight对象内部的,并且是不会随环境的改变而有所不同的。因此,一个Flyweight对象可以具有内部状态并可以共享。
??? 一个外部状态是随环境改变而改变的、不可共享的状态。Flyweight对象的外部状态必须由客户端保存,并在对象被创建后,在需要使用的时候再传入到Flyweight对象内部。
??? 外部状态不可以影响Flyweight对象的内部状。换句话说,它们是相互独立的。
Flyweight模式的应用
??? Flyweight模式在编辑器系统中大量使用。一个文本编辑器往往会提供很多种字体,而通常的做法是将每一个字母做成一个Flyweight对象。该对象的内部状态就是这个字母,而字母在文本中的位置和字模风格等其他信息这是外部状态。比如,字母a可能出现在文本的很多地方,虽然这些字母a的位置和字模风格不同,但是所有这些地方使用的都是同一个字母对象。这样一来,字母对象就可以在整个系统中共享。
单纯Flyweight模式的结构
在单纯Flyweight模式中,所有的Flyweight对象都是可以共享的。其类图如附件中图1所示:
?
单纯flyweight模式所涉及的角色如下:
复合Flyweight模式的结构
??? 在上面的单纯Flyweight模式中,所有的Flyweight对象都是单纯Flyweight对象,也就是说都是可以直接共享的。下面考虑一个较为复杂的情况,即将一些单纯Flyweight对象使用合成模式加以复合,形成复合Flyweight对象。这样的复合Flyweight对象本身不能共享,但是它们可以分解成单纯Flyweight对象,而后者则可以共享。
??? 复合Flyweight模式的类图如附件中图2所示。
?
??? 该模式涉及的角色有抽象Flyweight角色、ConcreteFlyweight角色、CompositeFlyweight角色、FlyweightFactory角色,以及客户端角色。
?
Flyweight应当在什么情况下使用
??? 当以下所有的条件都满足时,可以考虑使用Flyweight模式:
?? (1)??? 一个系统有大量的对象。
?? (2)??? 这些对象耗费大量的内存。
?? (3)??? 这些对象的状态中的大部分都可以外部化。
?? (4)??? 这些对象可以按照内部状态分成很多组,当把外部对象从对象中剔除时,每个组都可以仅用一个对象代替。
?? (5)??? 软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。
??? 最后,使用Flyweight模式需要维护一个记录了系统已有的所有共享单元的表,而这需要耗费资源。因此,应当在有足够多的Flyweight实例可供共享时才值得使用Flyweight模式。
怎样做到共享
??? 一个Flyweight对象之所以可以被很多的客户端共享,是因为它只含有可以共享的状态,而没有不可以共享的状态,这是可以使用Flyweight模式的重要前提。
??? 因此,问题转化为怎样才能重新设计这个常规类,使他能够复合Flyweight类的要求。要做到这一点,需要分两步走:
? (1)??? 将可以共享的状态和不可以共享的状态从此常规类中区分开来,将不可共享的状态类从类里剔除出去。
? (2)??? 这个类的创建过程必须由一个工厂对象加以控制。为了达到共享的目的,客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。这个工厂对象应当使用一个内部列表保存所有的已经创建出来的对象。当客户端请求一个新的对象时,工厂对象首先检查列表,看是否已经有一个对象。
Flyweight模式的优点和缺点
??? Flyweight模式的优点在于它大幅度的降低内存中对象的数量。但是,它做到这一点所付出的代价也很高:
?