享元模式
享元模式
一、享元模式是什么?
享元设计模式(FlyWeight Design Pattern):通过共享已有实例,来避免创建新的实例,减少空间消耗,提高资源利用率
享元,意思就是共享的对象、单元、元素等。
主要特点:
- 相同实例对象只保留一份,即享元对象
- 需要某个实例时,尽量共用享元对象
- 享元对象可以减少对象的数量
享元模式的本质就是缓存对象,减少资源消耗。
二、为什么要用享元模式?
享元模式,目的就是为了共享对象、减少资源的消耗。
使用享元模式,为的就是减少资源消耗、降低内存,提高资源利用率。
三、该如何用享元模式?
使用享元模式,需要注意几点:
- 享元对象应该是不可变的,即没有setter方法
- 享元对象会对所有地方都有影响
- 享元对象中不应该存在可变的信息,即有可能发生变化的内容
- 享元对象不应该被垃圾回收
- 享元对象的内部状态是不可变的,外部转台是可变的
比如,数据库连接池,用户名、密码、url这些属于享元对象的内部状态,不可变;
连接可用标记等属性,属于外部状态,是可变的,比如回收连接后,可用标记会设为true。
享元模式的几个角色包括:
- 抽象享元角色(FlyWeight):表示享元类的接口
- 具体享元角色(ConcreteFlyWeight):表示被共享的享元实例对象
- 非享元角色(Unsharable Flyweight):表示外部状态,区别于享元对象的内部状态,以参数形式注入享元对象
- 享元工厂(FlyWeightFactory):负责生成和管理享元对象的工厂
享元模式结构:
示例程序结构:
享元类:
1 | public class BigChar { |
享元工厂:
1 | public class BigCharFactory { |
享元使用:
1 | public class BigString { |
四、享元模式有什么优缺点?
优点:
- 共享相同对象,资源消耗低、利用率高
- 对象数量少,方便管理享元对象
缺点:
- 需要将共享对象分离出来,可能会使得程序变得复杂
五、享元和单例、缓存、对象池的区别
5.1 享元 vs. 单例
单例本质是为了控制实例的数量,重点在于数量。
享元关注的点是实例共享,重点在于共享,数量不是主要矛盾。
5.2 享元 vs. 缓存
缓存的作用是为了提高查询速度,目的在于提高效率。
享元的目标是为了降低资源消耗,主要关注点是资源的利用率。
5.3 享元 vs. 对象池
对象池主要用于管理对象,重点在于对一批对象进行管理分配回收。
享元主要还是为了对象的复用,在管理方面不是特别关注。
六、享元模式的实际应用
Integer:
- Java 中 Integer 默认缓存 -128 ~ 127 之间的数字对象
- Integer 的缓存对象是一开始就创建好的
String:
- Java 中 String 对象会缓存到字符串常量池中,其他地方可以直接引用
- String 的常量池对象是动态创建的