享元模式(Flyweight Pattern)是对象的结构模式。享元模式以共享的方式高效地支持大量细粒度对象的创建。
享元对象能够做到共享的关键是区分内蕴状态和外蕴状态;内蕴状态就是指不随环境的改变而改变、可以共享的状态,外蕴状态是随环境的改变而改变,不可以共享的状态;因为外蕴状态不可以共享所以外蕴状态的保存时由客户端进行保存的,在需要的时候再传入到享元对象内部。
在日常的编辑器中,字体的大小样式都是可以改变的,但是字符是的值是一直不变的;输入的A,不管是斜体的还是黑体的它永远都是A。由此可以发现A的值是一个内蕴状态,而A的字体样式是一个外蕴状态。
/** * 字母的抽象接口 * @author zhangwei_david * @version $Id: Letter.java, v 0.1 2015年3月26日 下午3:51:13 zhangwei_david Exp $ */ public interface Letter { public void resetFont(String font); }
/** * * @author zhangwei_david * @version $Id: Character.java, v 0.1 2015年3月26日 下午3:59:01 zhangwei_david Exp $ */ public class Character implements Letter { private String value; public Character(String value) { super(); this.value = value; } /** * @see com.pattern.create.flyweight.Letter#resetFont(java.lang.String) */ @Override public void resetFont(String font) { System.out.println("字符" + value + "的字体是" + font); } }
/** * * @author zhangwei_david * @version $Id: CharacterFactory.java, v 0.1 2015年3月26日 下午4:09:01 zhangwei_david Exp $ */ public class CharacterFactory { private Map<String, Letter> characters = new HashMap<String, Letter>(); private static CharacterFactory instance = new CharacterFactory(); public static CharacterFactory getInstance() { return instance; } public Letter factory(String value) { if (characters.containsKey(value)) { return characters.get(value); } Letter letter = new Character(value); characters.put(value, letter); return letter; } public int getObjectSize() { return characters.size(); } }
/** * * @author zhangwei_david * @version $Id: Client.java, v 0.1 2015年3月26日 下午4:14:01 zhangwei_david Exp $ */ public class Client { /** * * @param args */ public static void main(String[] args) { CharacterFactory characterFactory = CharacterFactory.getInstance(); Letter letter1 = characterFactory.factory("a"); letter1.resetFont("斜体 10号"); Letter letter2 = characterFactory.factory("a"); letter2.resetFont("黑体 10号"); System.out.println(characterFactory.getObjectSize()); } }
字符a的字体是斜体 10号 字符a的字体是黑体 10号 1
可以发现实际创建的对象只有一个,而表象是两个
通过享元模式的定义可以发现不可变对象是天生的享元对象,所有虽说享元对象不一定是不可变的,但是往往将享元对象设计为一个不可变的对象。
什么时候使用享元模式
- 一个系统中有大量的对象
- 这些对象往往消耗大量内存资源
- 这些对象中的状态中大部分都可以外部化
- 这些对象可以按照内蕴状态可以分为很多组,当把外蕴状态从对象中剔除时,每一组可以仅适用一个对象替代
- 系统不依赖于这些对象的身份,换言之这些对象是不可分辨的。
当满足以上情况就可以使用享元模式。