java设计模式——享元模式
一. 定义与类型
定义:提供了减少对象数量从而改善应用所需的对象结构的方式,运用共享技术有效地支持大量细粒度的对象
类型:结构性
二. 使用场景
(1) 常常应用于系统底层的开发,以便解决系统的性能问题
(2) 系统有大量相似对象,需要缓冲池的场景
三. 优缺点
优点:
(1) 减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率
(2) 减少内存之外的其他资源占用
缺点:
(1) 关注内/外状态,关注线程安全问题
(2) 使系统,程序的逻辑复杂化
四.享元——扩展
内部状态
外部状态
五. 相关设计模式
享元模式和代理模式
代理模式就是代理一个类,如果生成这个代理类需要花费的资源和时间比较多,就可以使用享元模式,提高系统的速度
享元模式和单例模式
单例模式中的容器单例就是享元模式的一种使用
六. Coding
以一个业务场景为例,假设每年年底的时候公司中的部门经理都需要写年终报告,但是可能不止要报告一次,需要重复报告。
使用享元模式,可以很好的完成上面的例子。
先创建一个接口:
/** * @program: designModel * @description: * @author: YuKai Fan * @create: 2019-02-12 10:01 **/ public interface Emplyee { void report(); }
再创建一个经理实体类,来实现接口
/** * @program: designModel * @description: 部门manager * @author: YuKai Fan * @create: 2019-02-12 10:01 **/ public class Manager implements Emplyee { public void report() { System.out.println(reportContent); } private String title = "部门经理"; private String department;//部门 private String reportContent;//报告内容 public Manager(String department) { this.department = department; } public void setReportContent(String reportContent) { this.reportContent = reportContent; } }
在创建一个员工工厂,通过工厂在获取manager,因为只需要manager做报告,不需要employee。
/** * @program: designModel * @description: 员工工厂 * @author: YuKai Fan * @create: 2019-02-12 10:04 **/ public class EmployeeFactory {
//因为在享元模式中,一般要考虑线程安全问题,但是还是要看业务场景来使用 private static final Map<String, Emplyee> EMPLYEE_MAP = new HashMap<String, Emplyee>(); public static Emplyee getManager(String department) { Manager manager = (Manager) EMPLYEE_MAP.get(department); if (manager == null) { manager = new Manager(department); System.out.print("创建部门经理:" + department); String reportContent = department + "部门汇报:此次报告的主要内容是。。。。"; manager.setReportContent(reportContent); System.out.println(" 创建报告:" + reportContent); EMPLYEE_MAP.put(department, manager); } return manager; } }
应用层:
/** * @program: designModel * @description: * @author: YuKai Fan * @create: 2019-02-12 10:08 **/ public class Test { private static final String departments[] = {"RD", "QA", "PM", "BD"}; public static void main(String[] args) { for (int i = 0; i < 10; i++) { String department = departments[(int) (Math.random() * departments.length)]; Manager manager = (Manager) EmployeeFactory.getManager(department); manager.report(); } } }
结果:
UML类图:
从结果可以看出,当部门经理做报告时只需要创建一次即可,下次不需要再次创建。减少了对象的创建
在上面的代码例子中,department相当于外部状态。因为它依赖于外部的传入,为了方便理解,创建一个title属性,它就是一个内部状态,它不随外部状态department的变化而变化。
七. 源码分析
(1)
Integer类就是典型的享元模式的例子
Integer.valueOf中有一个IntegerCache,上面的代码中就对传入的值进行判断。如果是从IntegerCache中取出就直接返回,否则就new一个Integer对象。这也就是如果传入的int值不在固定的范围类,它们做==的时候一定是false,因为不是同一个对象。其中low=-128,high=127.
还有Long类的valueOf,也是同上的道理。
(2)
tomcat中的GenericObjectPoolConfig连接池