news 2026/2/27 16:06:01

二十三种设计模式(十一)--享元模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
二十三种设计模式(十一)--享元模式

享元模式 Flyweight

享元模式为了解决多个对象占用内存大的问题, 采用多个对象共享对象池中的原始对象的方式, 提高性能, 节省程序开销

享元模式, 字面意思就很恰当, 共享元素.
主要角色有两个, 一个是基于共同接口的对象类, 另一个是工厂方法用来输出对象池中的对象
共享的元素必须是对象实例化后成员始终不变的, 所有会在运行时会变化的成员都要通过传参的形式从外部注入, 不能预先定义在享元类中.

interfaceBikeInterface{voidrun();}// 具体享元类(封装内部状态,私有化并提供访问方法)classConcreteBikeimplementsBikeInterface{// 内部状态:可共享、不可变privatefinalStringbrand;// 私有化+final,确保不可变// 构造方法初始化内部状态publicConcreteBike(Stringbrand){this.brand=brand;}publicStringgetBrand(){returnbrand;}@Overridepublicvoidrun(){System.out.println(brand+"牌自行车");}}// 享元工厂, 建立对象存储池, 池内对象不重复classBikeFlyweightFactory{privateMap<String,BikeInterface>bikePool=newHashMap<>();// 获取对象时, 相同的对象直接从共享池中取出publicConcreteBikegetBike(Stringbrand){if(!bikePool.containsKey(brand)){bikePool.put(brand,newConcreteBike(brand));}return(ConcreteBike)bikePool.get(brand);}publicvoidsize(){System.out.println("size = "+bikePool.size());}}

调用测试:

publicclassFlyweightPattern{publicstaticvoidmain(String[]args){BikeFlyweightFactorybf=newBikeFlyweightFactory();ConcreteBikea=bf.getBike("飞鸽");ConcreteBikeb=bf.getBike("上海");ConcreteBikec=bf.getBike("飞鸽");bf.size();// 这里对象a和c共享一个对象, 节省了开销a.run();b.run();c.run();}}

运行结果

size = 2 飞鸽牌自行车 上海牌自行车 飞鸽牌自行车

将不可变的内部状态抽离并共享,减少对象实例化的数量,这是享元模式最核心的价值。

注意要点:

  1. 内部状态必须保证不可变
    这是享元模式的第一铁律:内部状态若可变,一个客户端修改状态会导致所有共享该对象的客户端受影响,引发逻辑混乱。
  2. 外部状态由客户端持有,享元对象不持有外部状态的引用(避免内存泄漏或状态耦合),仅在执行方法时临时使用。
    若外部状态较多,可封装为独立的外部状态对象,而非零散的方法参数,提升代码可读性
  3. 享元池的选型与性能权衡
    避免使用ArrayList等需要遍历的集合存储享元对象(时间复杂度O(n)),推荐使用HashMap/ConcurrentHashMap(以内部状态为 key,时间复杂度O(1)),尤其在对象数量较多时。
  4. 注意享元池的内存上限:若共享对象过多,可能导致享元池占用内存过大,可结合缓存淘汰策略(如 LRU)限制池的大小。

享元模式与线程池、数据库连接池容易混淆,二者是相似但不同的概念:

享元模式:聚焦于对象的内部状态共享,对象是无状态 / 不可变的,共享的是 “对象本身”。
池化技术:聚焦于对象的复用,对象是有状态的(如线程的执行状态、连接的占用状态),池化的是 “对象的使用权”(用完后归还池,而非永久共享)。

二者的共同思想是 “减少对象创建”,但享元模式是逻辑层面的状态共享,池化技术是物理层面的对象复用。

享元模式遵循的设计原则

单一职责原则 享元对象:仅负责封装内部状态并实现自身行为,不处理外部状态的管理。 享元工厂:仅负责创建和复用享元对象,不参与享元对象的业务逻辑。 外部状态:由客户端或独立的外部状态类管理,与享元对象解耦。 开闭原则 新增具体享元类(如新增ElectricBike实现BikeInterface)时, 无需修改享元工厂的核心逻辑(只需工厂能识别新的内部状态 key),符合 “对扩展开放、对修改关闭”。 里氏替换原则 所有具体享元类都实现抽象享元接口,客户端可使用具体享元对象替换抽象享元对象, 而不影响程序逻辑(如ConcreteBike替换BikeInterface)。 迪米特法则(LoD) 客户端仅需与享元工厂交互获取享元对象,无需了解享元池的内部实现(如HashMap的存储逻辑), 降低了客户端与工厂的耦合。 复用原则(DRY 原则) 核心目标是复用相同内部状态的对象,避免重复创建,减少代码冗余和内存开销, 是复用原则的典型体现。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/21 14:22:17

QCustomPlot绘制曲线

QCustomPlot绘制曲线 1、前言2、下载 QCustomPlot 库3、在项目中使用QCustomPlot库3.1 把 QCustomPlot 加入你的 .pro 文件3.2 UI 里放一个 Widget 并提升为 QCustomPlot3.3 初始化 QCustomPlot 4、项目文件4.1 .pro文件4.2 .h文件4.3 .cpp文件 5、总结 1、前言 记录一下QCust…

作者头像 李华
网站建设 2026/2/27 6:56:57

消费级GPU玩转轻量级VLM:3步完成SmolVLM高效微调实战

消费级GPU玩转轻量级VLM&#xff1a;3步完成SmolVLM高效微调实战 【免费下载链接】smol-vision 项目地址: https://ai.gitcode.com/hf_mirrors/merve/smol-vision 在当今AI模型参数动辄百亿的时代&#xff0c;视觉语言模型&#xff08;VLM&#xff09;的个性化定制似乎…

作者头像 李华
网站建设 2026/2/21 4:57:53

基于Verilog的8位RISC CPU设计与实现全解析

基于Verilog的8位RISC CPU设计与实现全解析 【免费下载链接】8-bits-RISC-CPU-Verilog Architecture and Verilog Implementation of 8-bits RISC CPU based on FSM. 基于有限状态机的8位RISC&#xff08;精简指令集&#xff09;CPU&#xff08;中央处理器&#xff09;简单结构…

作者头像 李华
网站建设 2026/2/25 16:38:40

Wan2.2-T2V-5B可用于天气预报动态可视化播报

Wan2.2-T2V-5B可用于天气预报动态可视化播报 你有没有经历过这样的场景&#xff1a;打开天气App&#xff0c;看到“局部有雨”四个字&#xff0c;却完全想象不出雨到底下在哪儿&#xff1f;&#x1f327;️ 而另一边&#xff0c;气象台的专家正对着复杂的雷达图分析云团移动路径…

作者头像 李华
网站建设 2026/2/27 7:04:38

SwiftUI内存管理深度解析:如何彻底解决List滚动崩溃问题?

SwiftUI内存管理深度解析&#xff1a;如何彻底解决List滚动崩溃问题&#xff1f; 【免费下载链接】Kingfisher 一款轻量级的纯Swift库&#xff0c;用于从网络下载并缓存图片。 项目地址: https://gitcode.com/GitHub_Trending/ki/Kingfisher Kingfisher作为Swift生态中广…

作者头像 李华
网站建设 2026/2/24 7:43:44

揭秘MS-720 Teams Agent开发:5个你必须掌握的关键接口

第一章&#xff1a;MS-720 Teams Agent开发概述Microsoft Teams 平台通过 MS-720 认证体系推动了智能代理&#xff08;Agent&#xff09;生态的发展&#xff0c;使得开发者能够构建具备上下文感知、任务自动化与自然语言交互能力的智能服务。Teams Agent 作为集成于协作环境中的…

作者头像 李华