设计模式教程:享元模式(Flyweight Pattern)

news/2025/2/22 22:40:49/

享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少对象的创建数量,避免大量相似对象的内存占用。它通过共享对象来有效支持大量的细粒度对象,尤其是在需要大量类似对象的情况下,享元模式可以显著节省内存。

1. 享元模式的定义

享元模式通过将相同或相似的对象共享来节省内存,尤其适用于那种大量相似对象的场景。例如,在绘图软件中,每个图形(如圆形、方形等)都可能有颜色、大小等不同的属性。享元模式可以将共享的部分提取出来,将不变的部分共享,而将变化的部分放入外部的状态中。

2. 享元模式的角色
  • Flyweight(享元角色):定义共享对象的接口,并提供存储共享状态的方法。
  • ConcreteFlyweight(具体享元角色):实现享元角色接口,负责存储并管理共享的状态。
  • UnsharedConcreteFlyweight(非共享享元角色):某些状态无法共享时,会有一些非共享享元类用于存储非共享的状态。
  • FlyweightFactory(享元工厂角色):负责管理享元对象的创建和共享。确保享元对象的复用,并在需要时返回相同的享元实例。
3. 享元模式的核心思想
  • 共享:将多个对象中共享的部分提取出来,放到一个共享池中,供多个对象复用。
  • 外部状态:将不变的部分共享给所有对象,而可变的部分则交给外部来管理。
4. 享元模式的应用场景
  • 当系统有大量相似对象需要存储时,特别是当这些对象的状态占用大量内存时。
  • 对象的状态可以分为共享的部分和不共享的部分,不共享部分可以通过外部传入。
  • 对象状态的共享可以显著节省内存。
5. 享元模式的结构图
 +-------------------+|    Flyweight      |<-----------------------++-------------------+                        || - sharedState     |                        || + operation()     |                        |+-------------------+                        |^                                     ||                                     |+------------------------+                   || ConcreteFlyweight      |                   |+------------------------+                   || - sharedState          |                   || + operation()          |                   |+------------------------+                   |^                                     ||                                     |+--------------------------+                 || UnsharedConcreteFlyweight|-----------------++--------------------------+| - uniqueState            || + operation()            |+--------------------------+
6. 享元模式的代码示例

棋盘游戏 为例,假设我们有大量的棋子,每个棋子都需要设置颜色和类型。享元模式可以减少内存使用,避免重复创建相同类型和颜色的棋子对象。

享元模式实现:
// 享元角色:Flyweight(享元类)
interface ChessPiece {void display(String position);
}// 具体享元角色:ConcreteFlyweight(具体享元类)
class ConcreteChessPiece implements ChessPiece {private String type; // 棋子的类型public ConcreteChessPiece(String type) {this.type = type;}@Overridepublic void display(String position) {System.out.println("棋子类型:" + type + ", 位置:" + position);}
}// 非共享享元角色:UnsharedConcreteFlyweight(非共享享元类)
class UnsharedConcreteChessPiece implements ChessPiece {private String type;private String color; // 棋子的颜色(非共享部分)public UnsharedConcreteChessPiece(String type, String color) {this.type = type;this.color = color;}@Overridepublic void display(String position) {System.out.println("棋子类型:" + type + ", 颜色:" + color + ", 位置:" + position);}
}// 享元工厂:FlyweightFactory(享元工厂)
class ChessPieceFactory {private Map<String, ChessPiece> chessPieceMap = new HashMap<>();public ChessPiece getChessPiece(String type) {ChessPiece piece = chessPieceMap.get(type);if (piece == null) {piece = new ConcreteChessPiece(type); // 如果工厂中没有该类型的棋子,就创建一个新的chessPieceMap.put(type, piece);System.out.println("创建新棋子:类型 " + type);}return piece;}
}public class FlyweightPatternExample {public static void main(String[] args) {// 享元工厂ChessPieceFactory chessPieceFactory = new ChessPieceFactory();// 棋盘上的棋子ChessPiece whitePawn = chessPieceFactory.getChessPiece("兵");whitePawn.display("A1");ChessPiece blackKnight = chessPieceFactory.getChessPiece("马");blackKnight.display("B2");ChessPiece whitePawn2 = chessPieceFactory.getChessPiece("兵");whitePawn2.display("A2");// 非共享棋子ChessPiece blackQueen = new UnsharedConcreteChessPiece("皇后", "黑色");blackQueen.display("D1");}
}
代码解析:
  1. ChessPiece:定义了棋子的接口,所有棋子类都需要实现该接口的 display 方法。
  2. ConcreteChessPiece:是具体享元类,表示共享的部分。所有相同类型的棋子都会共享这部分数据。
  3. UnsharedConcreteChessPiece:是非共享享元类,表示无法共享的部分(如棋子的颜色等),每个棋子实例都有唯一的颜色。
  4. ChessPieceFactory:享元工厂,负责创建和管理享元对象。它缓存了已经创建的棋子对象,并在需要时返回已有的共享对象。

7. 享元模式的优缺点

优点:
  • 节省内存:通过共享相同的对象,减少了对象的数量,从而节省内存空间。
  • 提高性能:在对象频繁创建和销毁的情况下,享元模式可以有效提高程序的性能。
  • 灵活性高:可以动态地调整共享对象的状态,并根据外部状态来决定是否使用共享对象。
缺点:
  • 复杂性增加:为了共享对象,需要引入享元工厂、享元接口等多个类,增加了系统的复杂性。
  • 不适合所有场景:如果共享的对象非常少或者共享状态不容易提取时,使用享元模式可能得不偿失。

8. 总结

享元模式通过对象共享,减少了大量相似对象的内存开销,适用于大规模对象共享的场景。它通过将共享部分提取到外部并由享元工厂管理来优化内存使用。享元模式特别适合内存有限且需要处理大量细粒度对象的场景。

版权声明
  1. 本文内容属于原创,欢迎转载,但请务必注明出处和作者,尊重原创版权。
  2. 转载时,请附带原文链接并注明“本文作者:扣丁梦想家
  3. 禁止未经授权的商业转载。

如果您有任何问题或建议,欢迎留言讨论。


http://www.ppmy.cn/news/1574264.html

相关文章

Maven导入hutool依赖报错-java: 无法访问cn.hutool.core.io.IORuntimeException 解决办法

欢迎大家来到我的博客~欢迎大家对我的博客提出指导&#xff0c;有错误的地方会改进的哦~点击这里了解更多内容 目录 一、报错二、解决办法 一、报错 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-captcha</artifactId> </de…

【HeadFirst系列之HeadFirst设计模式】第7天之命令模式:封装请求,轻松实现解耦!

命令模式&#xff1a;封装请求&#xff0c;轻松实现解耦&#xff01; 大家好&#xff01;今天我们来聊聊设计模式中的命令模式&#xff08;Command Pattern&#xff09;。如果你曾经需要将请求封装成对象&#xff0c;或者希望实现请求的撤销、重做等功能&#xff0c;那么命令模…

R语言NIMBLE、Stan和INLA贝叶斯平滑及条件空间模型死亡率数据分析:提升疾病风险估计准确性...

全文链接&#xff1a;https://tecdat.cn/?p40365 在环境流行病学研究中&#xff0c;理解空间数据的特性以及如何通过合适的模型分析疾病的空间分布是至关重要的。本文主要介绍了不同类型的空间数据、空间格点过程的理论&#xff0c;并引入了疾病映射以及对空间风险进行平滑处理…

Jupyter里面的manim编程学习

1.Jupyterlab的使用 因为我之前一直都是使用的vscode进行manim编程的&#xff0c;但是今天看的这个教程使用的是Jupyter&#xff0c;我也很是好奇这个manim在Jupyter这样的交互式下面会生成怎么样的效果&#xff0c;所以今天尝试了jupyter&#xff0c;并且对于两个进行比较和说…

OpenSSL实验

文章目录 一、OpenSSL安装二、OpenSSL配置常见路径查找配置文件的方法示例**1. 配置文件结构****2. 主要段落及其作用****(1) 默认段&#xff08;Default Section&#xff09;****(2) OID段&#xff08;OID Section&#xff09;****(3) CA相关段&#xff08;CA Section&#xf…

C++ 设计模式-备忘录模式

游戏存档实现&#xff0c;包括撤销/重做、持久化存储、版本控制和内存管理 #include <iostream> #include <memory> #include <deque> #include <stack> #include <chrono> #include <fstream> #include <sstream> #include <ct…

在低功耗MCU上实现人工智能和机器学习

作者&#xff1a;Silicon Labs 人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;技术不仅正在快速发展&#xff0c;还逐渐被创新性地应用于低功耗的微控制器&#xff08;MCU&#xff09;中&#xff0c;从而实现边缘AI/ML解决方案。这些MCU是许多嵌入式…

html中iframe标签 隐藏滚动条

iframe 隐藏滚动条 1. 直接隐藏的策略&#xff1a; frame 有个属性 scrolling&#xff0c;直接设置 scrolling‘no’ 即可隐藏 scrollbar。这样iframe就不能滚动了。 <iframe src"https://www.baidu.com/" scrolling"no"></iframe>2. 修改 i…