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();
        }
    }
}

结果:

java设计模式——享元模式

UML类图:

java设计模式——享元模式

从结果可以看出,当部门经理做报告时只需要创建一次即可,下次不需要再次创建。减少了对象的创建

在上面的代码例子中,department相当于外部状态。因为它依赖于外部的传入,为了方便理解,创建一个title属性,它就是一个内部状态,它不随外部状态department的变化而变化。

七. 源码分析

(1)

Integer类就是典型的享元模式的例子

java设计模式——享元模式

Integer.valueOf中有一个IntegerCache,上面的代码中就对传入的值进行判断。如果是从IntegerCache中取出就直接返回,否则就new一个Integer对象。这也就是如果传入的int值不在固定的范围类,它们做==的时候一定是false,因为不是同一个对象。其中low=-128,high=127.

java设计模式——享元模式java设计模式——享元模式

还有Long类的valueOf,也是同上的道理。

(2)

tomcat中的GenericObjectPoolConfig连接池