1、享元模式以共享的方式高效地支持大量的细粒度对象
2、Java中的String类型就是使用了享元模式
- String对象是final类型,对象一旦创建就不可改变
- JAVA会确保一个字符串常量在常量池中只有一个拷贝
String a = "abc";
String b = "abc";
System.out.println(a==b);//true
- 这样的设计避免了在创建N多相同对象时所产生的不必要的大量的资源消耗
3、享元模式的结构
- 采用一个共享来避免大量拥有相同内容对象的开销
- 享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)
- 一个内蕴状态是存储在享元对象内部的,并且是不会随环境的改变而有所不同;一个享元可以具有内蕴状态并可以共享
- 一个外蕴状态是随环境的改变而改变的、不可以共享的
- 享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部
- 外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的
4、享元模式可以分成单纯享元模式和复合享元模式两种形式
单纯享元模式
- 所有的享元对象都是可以共享的
- 客户端调用
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
FlyweightFactory factory = new FlyweightFactory();
Flyweight fly = factory.factory(new Character('a'));
fly.operation("First Call");
fly = factory.factory(new Character('b'));
fly.operation("Second Call");
fly = factory.factory(new Character('a'));
fly.operation("Third Call");
}
}
- 执行结果
- 申请了三个对象,实际创建的享元对象只有两个,这就是共享的含义
复合享元模式
- 将一些单纯享元使用合成模式加以复合,形成复合享元对象
- 这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享
- 抽象享元角色类
- 具体享元角色类
- 复合享元对象是由单纯享元对象通过复合而成的
- 享元工厂角色提供两种不同的方法,一种用于提供单纯享元对象,另一种用于提供复合享元对象
- 客户端调取
- 执行结果
结果说明
- 一个复合享元对象的所有单纯享元对象元素的外蕴状态都是与复合享元对象的外蕴状态相等的。即外运状态都等于Composite Call
- 一个复合享元对象所含有的单纯享元对象的内蕴状态一般是不相等的。即内蕴状态分别为b、c、a
- 复合享元对象是不能共享的。即使用相同的对象compositeState通过工厂分别两次创建出的对象不是同一个对象
- 单纯享元对象是可以共享的。即使用相同的对象state通过工厂分别两次创建出的对象是同一个对象
4、享元模式的优缺点
- 享元模式的优点在于它大幅度地降低内存中对象的数量
- 享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化
- 享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长