享元模式(Flyweight Pattern),是对象池的一种体现,也是 GoF 的 23 种设计模式中的一种结构型设计模式。
享元模式 主要用于减少创建对象的数量,以减少内存占用和提高性能。它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式 尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
~
本篇内容包括:关于享元模式、享元模式 Demo
文章目录
- 一、关于享元模式
- 1、关于享元模式
- 2、关于享元模式的构成
- 3、关于享元模式的XML
- 4、关于享元模式的应用场景
- 5、关于享元模式在 Java 中的应用
- 6、关于享元模式的优缺点
- 二、享元模式 Demo
- 1、Demo 设计
- 2、Demo 实现
一、关于享元模式
1、关于享元模式
享元模式(Flyweight Pattern),是对象池的一种体现,也是 GoF 的 23 种设计模式中的一种结构型设计模式。
享元模式 主要用于减少创建对象的数量,以减少内存占用和提高性能。它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式 尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
2、关于享元模式的构成
享元模式主要包含四种角色:
- 抽象享元(Flyweight)角色:是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
- 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
- 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
- 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
3、关于享元模式的XML
4、关于享元模式的应用场景
当系统中多处需要同一组信息时,可以吧这些信息封装到一个对象中,然后对该对象进行缓存,这样,一个对象就可以提供给多处需要使用的地方,避免大量同一对象多次创建,消耗大量内存空间。
享元模式其实就是工厂模式的一个改进机制,享元模式同样要求创建一个或一组对象,并且就是通过工厂方法生成对象的,只不过享元模式中为工厂方法增加了缓存这一功能。主要总结为以下应用场景:
- 常常应用于系统底层的开发,以便解决系统的性能问题。
- 系统有大量相似的对象、需要缓存池的场景。
在生活中的享元模式也很常见,比如中介机构的房源共享,再比如全国社保联网。
5、关于享元模式在 Java 中的应用
在 Java 中最直观的享元模式就是在 Boolean,Byte,Integer,Long,Character 这些包装类中,他们都提供了valueOf()方法。
比如:Long 的 valueOf() 方法会缓存数值 -127~128 之间的 Long 对象,在这个范围之间就会直接在这个里面去取,大于这个范围才会去 new Long 对象
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
Byte,Short,Long 的范围是 -127~128 之间。
Character 是 0~127 之间。
Integer 是 -127~128 之间,最小值不能改变,但是最大值可以通过虚拟机参数进行改变。-Djava.long.Intger.IntegerCache.high 来改变
Boolean 缓存了 TRUE 和 FALSE
6、关于享元模式的优缺点
# 享元模式的优点:
- 减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率;
- 减少内存之外的其它资源占用。
# 享元模式的缺点:
- 关注内、外部状态、关注线程安全问题;
- 使系统、程序复杂化。
二、享元模式 Demo
1、Demo 设计
俄罗斯方块有不同的形状,我们可以对这些形状向上抽取出 AbstractBox,用来定义共性的属性和行为。
接下来就是定义不同的形状了,IBox类、LBox类、TBox类等。
提供了一个工厂类(BoxFactory),用来管理享元对象(也就是 AbstractBox 子类对象),该工厂类对象只需要一个,所以可以使用单例模式。并给工厂类提供一个获取形状的方法。
2、Demo 实现
# AbstractBox 抽象享元角色
public abstract class AbstractBox {
public abstract String getShape();
public void display(String color) {
System.out.println("方块形状:" + this.getShape() + " 颜色:" + color);
}
}
# IBox/LBox/TBox 具体享元角色
public class IBox extends AbstractBox {
@Override
public String getShape() {
return "I";
}
}
public class LBox extends AbstractBox {
@Override
public String getShape() {
return "L";
}
}
public class TBox extends AbstractBox {
@Override
public String getShape() {
return "T";
}
}
# BoxFactory 享元工厂
public class BoxFactory {
private static HashMap<String, AbstractBox> map;
private BoxFactory() {
map = new HashMap<String, AbstractBox>();
AbstractBox iBox = new IBox();
AbstractBox lBox = new LBox();
AbstractBox oBox = new OBox();
map.put("I", iBox);
map.put("L", lBox);
map.put("O", oBox);
}
public static final BoxFactory getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final BoxFactory INSTANCE = new BoxFactory();
}
public AbstractBox getBox(String key) {
return map.get(key);
}
}