设计模式十一之享元模式

  在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈。这些对象有很多相似的地方,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源,这就是享元模式的产生背景。

1. 模式的定义与特点

1.1 模式的定义

  享元模式(Flyweight):运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。

1.2 模式的特点

  享元模式的优点有:
    1. 相同对象主要保存一份,降低系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力;
    2. 减少内存之外的其他资源的占用

  享元模式的缺点有:
    1. 关注内、外部状态,关注线程安全问题;
    2. 使系统、程序的逻辑复杂化。

1.3 模式的使用场景

  1. 常常应用于系统底层的开发,以便解决系统的性能问题;
  2. 系统有大量相似对象、需要缓冲池的场景。

2. 模式的结构与实现

  享元模式中存在以下两种状态:
    1. 内部状态:不会随着环境的改变而改变的可共享部分;
    2. 外部状态:随着环境改变而改变的不可共享的部分,享元模式实现的要领就是要区分这两种状态,并将外部状态外部化。

2.1 模式的结构

  享元模式的主要角色如下:
    1. 抽象享元角色(Flyweight):是所有具体享元类的基类,为具体享元类规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法注入;
    2. 具体享元角色(Concrete Flyweight):实现抽象享元角色中定义的接口;
    3. 是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中;
    4. 享元工厂角色(Flyweight Factory):负责创建和管理享元角色,当客户请求一个享元角色时,享元工厂检查系统中是否存在符合条件的享元对象,如果存在则返回给客户,如果不存在,则创建一个新的享元对象。

享元模式类UML

2.2 模式的实现

抽象享元

/**
 * 抽象享元 - 员工类
 */
public interface Employee {

    /**
     * 作报告
     */
    void report();

}

具体享元*

/**
 * 具体享元 - 经理类
 */
public class Manager implements Employee {

    private ReportInfo info;

    public Manager(ReportInfo info) {
        this.info = info;
    }

    @Override
    public void report() {
        System.out.println("部门:" + info.getDepartment() + ", 报告内容为:"
                + info.getReportContent());
    }

}

非享元角色

/**
 * 非享元角色 - 报告内容
 */
public class ReportInfo {

    private String department;
    private String reportContent;

    public ReportInfo() {
    }

    public ReportInfo(String department, String reportContent) {
        this.department = department;
        this.reportContent = reportContent;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public String getReportContent() {
        return reportContent;
    }

    public void setReportContent(String reportContent) {
        this.reportContent = reportContent;
    }
}

享元工厂

/**
 * 享元工厂
 */
public class EmployeeFactory {

    private static final Map<String, Employee> EMPLOYEE_MAP = new HashMap<>();

    public static Employee getManger(ReportInfo info) {
        Manager manager = (Manager) EMPLOYEE_MAP.get(info.getDepartment());

        if (manager == null) {
            manager = new Manager(info);
            System.out.println("创建了部门经理:" + info.getDepartment());
            EMPLOYEE_MAP.put(info.getDepartment(), manager);
        }

        return manager;
    }

}

客户端

public class Client {

    public static void main(String[] args) {

        String[] departments = {"RD", "QA", "DB", "OP"};
        Stream.iterate(0, i -> i + 1).limit(10).forEach(i -> {
            String department = departments[(int) (Math.random() * departments.length)];
            String content = "conent_" + i + "...";
            Manager manger = (Manager) EmployeeFactory.getManger(new ReportInfo(department, content));
            manger.report();
        });

    }

}

# 运行结果如下:
创建了部门经理:OP
部门:OP, 报告内容为:conent_0...
部门:OP, 报告内容为:conent_0...
创建了部门经理:DB
部门:DB, 报告内容为:conent_2...
创建了部门经理:RD
部门:RD, 报告内容为:conent_3...
部门:RD, 报告内容为:conent_3...
创建了部门经理:QA
部门:QA, 报告内容为:conent_5...
部门:QA, 报告内容为:conent_5...
部门:DB, 报告内容为:conent_2...
部门:QA, 报告内容为:conent_5...
部门:RD, 报告内容为:conent_3...

3. 模式在开源软件中的应用

3.1 java.lang.Integer 类

public final class Integer extends Number implements Comparable<Integer> {
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
}

  如果在 -128 - 127 之间就直接从缓存中获取,否则就创建新的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值