一.定义
使用共享对象可有效地支持大量细粒度的对象。
- 细粒度的对象
- 共享对象
二.类图
- Flyweight抽象享元角色。简单说就是一个产品的抽象类,同时定义出对象的外部状态和内部状态的接口或实现。
- ConcreteFlyweight具体享元角色。具体的一个产品类,实现抽象角色定义的业务。该角色中需要注意的是内部状态处理应该与环境无关,不应该出现一个操作改变了内部状态,同时修改了外部状态,这是绝对不允许的。
- UnsharedConcreteFlyweight不可共享的享元角色。不存在外部状态或者安全要求(如线程安全)不能够使用共享技术的对象,该对象一般不会出现在享元工厂中。
- FlyweightFactory享元工厂。构造一个池容器,同时提供从池中获得对象的方法。
三.优点
大大减少应用程序创建的对象,降低程序内存占用,增强了程序性能。
四.缺点
提高了系统复杂性,需要分离出外部状态和内部状态,而且外部状态具有固化特性,不应该内状态改变而改变,否则导致系统的逻辑混乱。
五.应用场景
- 系统中存在大量的相似对象。
- 细粒度的对象都具备较接近的外部状态,且内部状态与环境无关,也就是说对象没有特定身份。
- 需要缓冲池的场景。
六.注意事项
- 线程安全问题。享元对象数量太少,多线程情况下每个线程都到对象池中获得对象,然后都去修改其属性,于是就出现一些问题。享元模式让我们使用共享技术,Java多线程使用会提高效率但会带来安全问题,如何设计来避免没有标准答案,只有依靠经验,在需要的地方考虑一下线程,在大部分的场景下都不用考虑。同时,在使用享元模式时,对象池中的享元对象尽量多,多到足够满足业务为止。
- 注意性能平衡。尽量使用Java基本类型作为外部状态,效率会比使用复合对象高很多。
- 享元模式可以实现对象池,但两者还是有比较大的区别的。对象池着重在对象的复用上,池中每个对象是可替换的,从同一个池中获得A对象和B对象对客户端来说是完全相同的,它主要解决复用,而享元模式主要解决的是对象的共享问题,如何建立多个可共享的细粒度对象则是其关注的重点。