运用共享技术有效地支持大量细粒度的对象。
FlyWeight是一个共享对象,它可以同时在多个场景(context)中使用,并且在每个场景中flyweight都可以作为一个独立的对象——这一点与非共享的实例没有区别。flyweight不能对它所运行的场景做出任何假充,这里的关键概念是内部状态和外部状态之间的区别是。内部状态存储于flyweight中,它包含了独立于flyweight场景的信息,这些信息使得flyweight可以被共享。而外部状态取决于flyweight场景,并根据场景变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给flyweight.
Flyweight模式对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模。例如,文档编辑器可以为字母表中的每一个字母创建一个flyweight.
Flyweight模式的有效性很大程度上取决于如何使用它以及在何处使用它。当以下情况都成立时使用Flyweight:
1、一个应用程序使用了大量的对象。
2、完全由于使用大量的对象,造成很大的存储开销。
3、对象的大多数状态都可变为外部状态。
4、如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
5、应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
存储节约由以下几个因素决定:
1、因为共享,实例总数减少的数目。
2、对象内部状态的平均数目。
3、外部状态是计算的还是存储的。
共享的Flyweight越多,存储节约也就越多。节约量随着共享状态的增多而增大。当对象使用大量的内部及外部状态,并且外部状态是计算出来的而非存储的时候,节约量将达到最大。所以人,可以用两种方法来节约存储:用共享减少内部状态的消耗,用计算时间换取对外部状态的存储。
Flyweight模式经常和Composite模式结合起来表示一个层次式结构,这一层次式结构是一个共享叶节点的图。共享的结果是,Flyweight的叶节点不能存储指向父节点的指针。而父节点的指针将传给Flyweight作为它的外部状态的一部分。这对于该层次结构中对象之间相互通讯的方式将产生很大的影响。
示例代码(以后补齐)
//
///////////////////////////////////////////////////////////////////// /
#pragma once
class Glyph
{
public :
virtual ~ Glyph();
virtual void Draw(Window * ,GlyphContext & );
virtual void SetFont(Font * ,GlyphContext & );
virtual Font * GetFont(GlyphContext & );
virtual void First(GlyphContext & );
virtual void Next(GlyphContext & );
virtual bool IsDone(GlyphContext & );
virtual Glyph * Current(GlyphContext & );
virtual void Insert(Glyph * ,GlyphContext & );
virtual void Remove(GlyphContext & );
protected :
Glyph();
} ;
/* ***********************************************************************
为了避免给每一个Glyph的字体属性都分配存储空间,我们可以将该属性外部存储于
GlyphContext对象中。GlyphContext是一个外部状态的存储库,它维持Glyph与字体
(以及其它一些可能的图形属性)之间的一种简单映射关系。对于任何操作,如果它
需要知道在给定场景下Glyph字体,都会有一个GlyphContext实例作为参数传递给它。
然后,该操作就可以查询GlyphContext以获取该场景中的字体信息了。这个场景取决
于Glyphp结构中的Glyph的位置。因此,当使用Glyph时,Glyph子类的迭代和管理操作
必须更新GlyphContext.
*********************************************************************** */
class GlyphContext
{
public :
GlyphContext();
virtual ~ GlyphContext();
virtual void Next( int step = 1 );
virtual void Insert( int quantity = 1 );
virtual Font * GetFont();
virtual void SetFont(Font * , int span = 1 );
private :
int _index;
BTree * _fonts;
} ;
/* ***********************************************************************
flyweight是我们需要的一个对象,它负责创建Glyph并确保对它们进行合理共享。
GlyphFactory类将实例化Character和其它类型的Glyph.我们只共享Character对象
组合的Glyph要少得多,并且它们的重要状态(如,它们的子节点)必定是内部的。
*********************************************************************** */
const int NCHARCODES = 128 ;
class GlyphFactory
{
public :
GlyphFactory();
virtual ~ GlyphFactory();
virtual Character * CreateCharacter( char );
virtual Row * CreateRow();
virtual Column * CreateColumn();
private :
Character * _character[NCHARCODES];
} ;
// _character数组包含一些指针,指向以字母代码为索引的CharacterGlyph。该数组
// 在构造函数中被初始化为零。
GlyphFactory::GlyphFactory()
{
for ( int i = 0 ;i < NCHARCODES; ++ i)
{
_character[i] = 0 ;
}
}
// CreateCharacter在字母符号数组中查找一个字符,如果存在的话,返回相应的Glyph。若
// 不存在,CreateCharacter就创建一个Glyph,将其放入数组中,并返回它:
Character * GlyphFactory::CreateCharacter( char c)
{
if ( ! _character[c])
{
_character[c] = new Character(c);
}
return _character[c];
}
// 其它操作仅需在每次被调用时实例化一个新对象,因为非字符的Glyph不能被共享
Row * GlyphFactory::CreateRow()
{
return new Row;
}
Column * GlyphFactory::CreateColumn()
{
return new Column;
}