把一些常用且不变的对象保存在一个队列里,每次优先从队列中取,没取到则新创建一个,再将它插入队列以供后续使用
- 定义:提供了减少对象数量从而改善应用所需的对象结构的方式,运用共享技术有效的支持大量细粒度的对象
- 类型:结构型
- 适用场景:
- 常常应用于系统底层的开发,以便解决系统的性能问题
- 系统有大量相似对象、需要缓冲池的场景
- 优点:
- 减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率
- 减少内存之外的其他资源占用
- 缺点:
- 关注内/外部状态、关注线程安全问题
- 使系统、程序的逻辑复杂化
- 扩展:
- 内部状态:在享元对象内部,并且不会随着环境改变而改变的共享部分,也就是外部环境怎么变我都不变,并且这个状态在享元对象内部
- 外部状态:随着环境改变而改变,这种状态是不能共享的状态,这个状态是记录在享元对象外部的
- 相关设计模式:
- 享元模式和代理模式:代理模式是代理一个类,如果生成这个代理类需要花费的资源和时间都比较多,那么就可以使用享元模式来提高程序的处理速度
- 享元模式和单例模式:容器单例就是享元模式和单例模式的结合
- 关键代码:用HashMap存储对象。用唯一标识码判断,如果内存中有,则返回这个唯一标识码所标识的对象。
Coding
/** * <p>享元模式 -- 抽象父类</p> */ public abstract class AbstractFlyWeight { /** * 模拟不同数据库的连接 */ public abstract void connection(); } /** * <p>自定义数据源驱动类</p> */ public class MyDbDriver extends AbstractFlyWeight { /** * 数据源驱动名称 == (对于具体的某个数据源驱动,其参数是固定的,因为无需重复new对象) */ private String driverName; public MyDbDriver(String driverName) { this.driverName = driverName; } @Override public void connection() { System.out.println(driverName + " -- 连接数据库"); } } /** * <p>数据源驱动工厂类</p> */ public class DbDriverFactory { private HashMap<String, MyDbDriver> dbDriverMap; private List<MyDbDriver> dbDrivers = new ArrayList<>(); public DbDriverFactory() { dbDriverMap = new HashMap<>(); } public MyDbDriver getDbDriver(String driverName) { MyDbDriver dbDriver; // 有的话,直接返回驱动对象 if (dbDriverMap.containsKey(driverName)) { System.out.println(driverName + "--> 数据源驱动实例已存在,无需再new,直接返回"); dbDriver = dbDriverMap.get(driverName); this.dbDrivers.add(dbDriver); return dbDriver; } dbDriver = new MyDbDriver(driverName); this.dbDriverMap.put(driverName, dbDriver); this.dbDrivers.add(dbDriver); return dbDriver; } public int size() { return dbDriverMap.size(); } public void showConns() { this.dbDrivers.forEach(d -> d.connection()); } }
测试
/** * <p>享元模式测试</p> * <p> * 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。 * 这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。 * 享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。 * <p>主要解决</p> * 在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来, * 如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。 */ public class FlyWeightTest { public static void main(String[] args) { DbDriverFactory factory = new DbDriverFactory(); // 工厂创建或取我们所需要的 MyDbDriver driver1 = factory.getDbDriver("mysql"); MyDbDriver driver2 = factory.getDbDriver("mongodb"); MyDbDriver driver3 = factory.getDbDriver("mysql"); MyDbDriver driver4 = factory.getDbDriver("postgresql"); MyDbDriver driver5 = factory.getDbDriver("oracle"); MyDbDriver driver6 = factory.getDbDriver("postgresql"); MyDbDriver driver7 = factory.getDbDriver("mysql"); System.out.println("================================"); factory.showConns(); System.out.println("================================"); System.out.println("工厂实例集大小:" + factory.size()); } } ===========运行结果============= mysql--> 数据源驱动实例已存在,无需再new,直接返回 postgresql--> 数据源驱动实例已存在,无需再new,直接返回 mysql--> 数据源驱动实例已存在,无需再new,直接返回 ================================ mysql -- 连接数据库 mongodb -- 连接数据库 mysql -- 连接数据库 postgresql -- 连接数据库 oracle -- 连接数据库 postgresql -- 连接数据库 mysql -- 连接数据库 ================================ 工厂实例集大小:4
注意:需要考虑到线程安全问题,可以加同步锁,使用线程安全的Map
UML
源码中应用
- java.lang.Integer
valueOf 方法,如果满足添加直接返回cache的对象,如果不是就重新new一个对象:
public static Integer valueOf(int i) { // -128 ~ 127 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } 测试 public class Test { public static void main(String[] args) { Integer a = Integer.valueOf(100); Integer b = 100; Integer c = Integer.valueOf(1000); Integer d = 1000; System.out.println("a==b:" + (a == b)); System.out.println("c==d:" + (c == d)); } } =======结果====== a==b:true c==d:false
- 思考 ThreadLocal 的应用是否是享元模式?