定义:运用共享技术有效地支持大量细粒度的的对象。
类型:对象结构型模式
类图:
FlyWeight模式的结构
享元对象的所有状态分成两类,内部状态和外部状态。
Flyweight执行时所需要的状态必定是内部的或者外部的状态,内部状态存储于ConcreteFlyweight对象中,而外部对象则由Client对象存储或计算,当用户调用Flyweight对象的操作时,将该状态传递给它。
现在通过一个面向对象的文本编辑器设计来说明享元模式的应用。假设我们要设计一个文本编辑器,而且它必须创建字符对象来表示文档中的每个字符,现在让我们考虑字符对象保持什么信息呢?如:字体、字体大小和位置等等信息。
一个文档通常包含许多字符对象,它们需要大容量的内存。值得我们注意的是一般字符都是由数字、字母和其他字符组成的(它们是固定的,可知的),这些字符对象可以共享字体和字体大小等信息,现在它们专有属性只剩下位置了,每个字符对象只需保持它们在文档中的位置就OK了,通过分析我们已经降低了编辑器的内存需求。
首先我们定义了一个字符享元类,其中符号、字体和字体大小都是内部状态,而位置则是外部状态。
// 抽象类 FlyWeight abstract class ICharacter { //字符享元 protected char symbol; protected int size; protected String font; public abstract void display(); }
接着我们定义具体字符A的享元类,并且对内部状态符号、字体和字体大小进行初始化,而且其他字符B到Z享元类都类似。
// ConcreteFlyweight class CharacterA extends ICharacter { //具体字符 A public CharacterA() { symbol = 'A'; size = 10; font = "宋体"; } @Override public void display() { System.out.println("symbol:" + symbol + " size:" + size + " font:" + font); } }
然后,我们定义一个字符工厂类,通过一个Map<java.lang.Character, Character>来保存字符对象,使用字符值来查找字符对象是否已经创建了,如果查找的字符对象已经存在,那么直接返回该对象,反之就创建字符对象实例。
// FlyweightFactory class class CharacterFactory { private static Map<Character, ICharacter> chs = new HashMap<Character, ICharacter>(); private static CharacterFactory instance = new CharacterFactory(); // 单例模式 private CharacterFactory() { }; /** * Checked the character whether existed or not,if the character existed, then directly returns, otherwise, instantiates a character object. * @param key * @return */ public ICharacter getCharacter(Character key) { ICharacter character = null; if (chs.containsKey(key)) { character = chs.get(key); } else { switch (key.charValue()) { case 'A': character = new CharacterA(); break; case 'B': character = new CharacterB(); break; case 'C': character = new CharacterC(); break; default: break; } chs.put(key, character); } return character; } public static CharacterFactory getInstance() { return instance; } }
Client代码
//Client public class FlyWeightClient { public static void main(String[] args) { String text = "ABCABBCC"; char[] chs = text.toCharArray(); CharacterFactory factory = CharacterFactory.getInstance(); for (int i = 0; chs != null && i < chs.length; i++) { char ch = chs[i]; Character key = Character.valueOf(ch); ICharacter character = factory.getCharacter(key); character.display(); } } }
适用场景
FlyWeight需要注意的问题
享元模式采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,我们要注意对象状态的处理,一定要正确地区分对象的内部状态和外部状态,这是实现享元模式的关键所在。
享元模式的优点在于它大幅度地降低内存中对象的数量。为了做到这一点,享元模式也付出了一定的代价: