享元模式

把一些常用且不变的对象保存在一个队列里,每次优先从队列中取,没取到则新创建一个,再将它插入队列以供后续使用

  • 定义:提供了减少对象数量从而改善应用所需的对象结构的方式,运用共享技术有效的支持大量细粒度的对象
  • 类型:结构型
  • 适用场景:
    •   常常应用于系统底层的开发,以便解决系统的性能问题
    •   系统有大量相似对象、需要缓冲池的场景
  • 优点:
    •   减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率
    •   减少内存之外的其他资源占用
  • 缺点:
    •   关注内/外部状态、关注线程安全问题
    •   使系统、程序的逻辑复杂化
  • 扩展:
    •   内部状态:在享元对象内部,并且不会随着环境改变而改变的共享部分,也就是外部环境怎么变我都不变,并且这个状态在享元对象内部
    •   外部状态:随着环境改变而改变,这种状态是不能共享的状态,这个状态是记录在享元对象外部的
  • 相关设计模式:
    •   享元模式和代理模式:代理模式是代理一个类,如果生成这个代理类需要花费的资源和时间都比较多,那么就可以使用享元模式来提高程序的处理速度
    •   享元模式和单例模式:容器单例就是享元模式和单例模式的结合
  • 关键代码:用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 的应用是否是享元模式?
posted @   wangzhilei  阅读(6)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示