享元模式(FlyWeight),运用共享技术有效的支持大量细粒度的对象。
内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的。
外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。
(1) 抽象享元角色:为具体享元角色规定了必须实现的方法,而外蕴状态就是以参数的形式通过此方法传入。在Java中可以由抽象类、接口来担当。
(2) 具体享元角色:实现抽象角色规定的方法。如果存在内蕴状态,就负责为内蕴状态提供存储空间。
(3) 享元工厂角色:负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键!
(4) 客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外蕴状态。
如果一个应用程序使用了大量的对象,而这些对象造成了很大的存储开销的时候就可以考虑是否可以使用享元模式。
例如,如果发现某个对象的生成了大量细粒度的实例,并且这些实例除了几个参数外基本是相同的,如果把那些共享参数移到类外面,在方法调用时将他们传递进来,就可以通过共享大幅度单个实例的数目。
典型的享元模式的例子为文书处理器中以图形结构来表示字符。一个做法是,每个字形有其字型外观, 字模 metrics, 和其它格式资讯,但这会使每个字符就耗用上千字节。取而代之的是,每个字符参照到一个共享字形物件,此物件会被其它有共同特质的字符所分享;只有每个字符(文件中或页面中)的位置才需要另外储存。以下程式用来解释上述的文件例子。这个例子用来解释享元模式利用只载立执行立即小任务所必需的资料,因而减少内存使用量。
publicenumFontEffect {
BOLD, ITALIC, SUPERSCRIPT, SUBSCRIPT, STRIKETHROUGH
}
publicfinalclassFontData {
/**
* A weak hash map will drop unused references to FontData.
* Values have to be wrapped in WeakReferences,
* because value objects in weak hash map are held by strong references. *
/
privatestaticfinalWeakHashMap<FontData, WeakReference<FontData>> FLY_WEIGHT_DATA =newWeakHashMap<FontData, WeakReference<FontData>>();
privatefinalintpointSize;
privatefinalString fontFace;
privatefinalColor color;
privatefinalSet<FontEffect> effects;
privateFontData(intpointSize, String fontFace, Color color, EnumSet<FontEffect> effects){this.pointSize = pointSize;
this.fontFace = fontFace;
this.color = color;
this.effects = Collections.unmodifiableSet(effects);
}
publicstaticFontData create(intpointSize, String fontFace, Color color, FontEffect... effects) { EnumSet<FontEffect> effectsSet = EnumSet.noneOf(FontEffect.class);
for(FontEffect fontEffect : effects) {
effectsSet.add(fontEffect);
}
// We are unconcerned with object creation cost, we are reducing overall memory consumptionFontData data =newFontData(pointSize, fontFace, color, effectsSet);
// Retrieve previously created instance with the given values if it (still) existsWeakReference<FontData> ref = FLY_WEIGHT_DATA.get(data);
FontData result = (ref !=null) ? ref.get() :null;// Store new font data instance if no matching instance exists
if(result ==null) {
FLY_WEIGHT_DATA.put(data,newWeakReference<FontData> (data));
result = data;
}
// return the single immutable copy with the given values
returnresult;
}
@Override
publicbooleanequals(Object obj) {
if(objinstanceofFontData) {
if(obj ==this) {
returntrue;
}
FontData other = (FontData) obj;
returnother.pointSize == pointSize && other.fontFace.equals(fontFace) && other.color.equals(color) && other.effects.equals(effects);
}
returnfalse;
}
@Override
publicinthashCode() {
return(pointSize * 37 + effects.hashCode() * 13) * fontFace.hashCode();
}
// Getters for the font data, but no setters. FontData is immutable.
}