收藏
0有用+1
0

享元模式

软件设计模式
享元模式(英语:Flyweight Pattern)是一种软件设计模式。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。
中文名
享元模式
外文名
Flyweight Pattern
性    质
软件设计模式
技术支持
共享技术
享元模式
共享技术的支持大量细粒度的对象

定义

播报
编辑
享元模式(FlyWeight),运用共享技术有效的支持大量细粒度的对象。
典型的享元模式的例子为文书处理器中以图形结构来表示字符。一个做法是,每个字形有其字型外观, 字模 metrics,和其它格式资讯,但这会使每个字符就耗用上千字节。取而代之的是,每个字符参照到一个共享字形物件,此物件会被其它有共同特质的字符所分享;只有每个字符(文件中或页面中)的位置才需要另外储存。 [1]

结构

播报
编辑

两个状态

内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的。
外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。

UML结构图

UML结构图
(1) 抽象享元角色:为具体享元角色规定了必须实现的方法,而外蕴状态就是以参数的形式通过此方法传入。在Java中可以由抽象类、接口来担当。
(2) 具体享元角色:实现抽象角色规定的方法。如果存在内蕴状态,就负责为内蕴状态提供存储空间。
(3) 享元工厂角色:负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键!
(4) 客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外蕴状态。 [2]

使用场景

播报
编辑
如果一个应用程序使用了大量的对象,而这些对象造成了很大的存储开销的时候就可以考虑是否可以使用享元模式。
例如,如果发现某个对象的生成了大量细粒度的实例,并且这些实例除了几个参数外基本是相同的,如果把那些共享参数移到类外面,在方法调用时将他们传递进来,就可以通过共享大幅度单个实例的数目。 [2]

示例

播报
编辑
典型的享元模式的例子为文书处理器中以图形结构来表示字符。一个做法是,每个字形有其字型外观, 字模 metrics, 和其它格式资讯,但这会使每个字符就耗用上千字节。取而代之的是,每个字符参照到一个共享字形物件,此物件会被其它有共同特质的字符所分享;只有每个字符(文件中或页面中)的位置才需要另外储存。以下程式用来解释上述的文件例子。这个例子用来解释享元模式利用只载立执行立即小任务所必需的资料,因而减少内存使用量。
public enum FontEffect { BOLD, ITALIC, SUPERSCRIPT, SUBSCRIPT, STRIKETHROUGH } public final class FontData { /**  * 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. * / private static final WeakHashMap<FontData, WeakReference<FontData>> FLY_WEIGHT_DATA = new WeakHashMap<FontData, WeakReference<FontData>>(); private final int pointSize; private final String fontFace; private final Color color; private final Set<FontEffect> effects; private FontData(int pointSize, String fontFace, Color color, EnumSet<FontEffect> effects){ this.pointSize = pointSize; this.fontFace = fontFace; this.color = color; this.effects = Collections.unmodifiableSet(effects); } public static FontData create(int pointSize, 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 consumption FontData data = new FontData(pointSize, fontFace, color, effectsSet); // Retrieve previously created instance with the given values if it (still) exists WeakReference<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, new WeakReference<FontData> (data)); result = data; } // return the single immutable copy with the given values return result; } @Override public boolean equals(Object obj) { if (obj instanceof FontData) { if (obj == this) { return true; } FontData other = (FontData) obj; return other.pointSize == pointSize && other.fontFace.equals(fontFace) && other.color.equals(color) && other.effects.equals(effects); } return false; } @Override public int hashCode() { return (pointSize * 37 + effects.hashCode() * 13) * fontFace.hashCode(); } // Getters for the font data, but no setters. FontData is immutable. }