设计模式之享元模式

ops/2024/9/24 23:26:40/

一、详细介绍

        享元模式是一种结构型设计模式,通过共享对象来有效支持大量细粒度对象的复用,减少内存消耗并提高性能。这种模式通过共享已经存在的相同或相似对象,而不是每次请求都创建新的对象,来减少系统中对象的数量,从而降低内存消耗和提高运行效率。

        享元模式的核心思想是运用共享技术来有效支持大量细粒度对象的复用。通常,我们会把一些可共享的、不变或变化很少的部分设计成共享对象,而把那些不能共享的、变化较多的部分设计为非共享对象。当系统需要创建大量相似对象时,通过享元模式,可以只创建少量的对象,同时确保程序性能。

二、使用场景

  1. 对象的大部分状态都可以外部化:如果一个对象的大部分状态都可以外部化,那么就可以通过参数传递的方式将这些状态传入对象内部,从而使得多个对象可以共享同一份内部数据。

  2. 一个应用程序使用了大量的对象:如果一个系统中存在大量的相似对象,由于这类对象数量巨大,将会造成很大的内存开销,此时可以考虑使用享元模式

  3. 对象的创建成本很高:如果对象的创建过程非常耗时或者耗资源,如涉及IO操作、数据库访问、复杂的计算等,可以使用享元模式来复用已创建的对象,避免重复创建带来的开销。

三、注意事项

  1. 区分内部状态和外部状态:内部状态是存储在享元对象内部并且不会随环境改变而改变的状态;外部状态是随环境改变而改变的、不可以共享的状态。享元模式只共享内部状态,不共享外部状态。

  2. 享元对象的线程安全:如果享元对象会被多个线程共享,那么需要考虑线程安全问题,可以通过同步机制或无锁数据结构等方式来保证线程安全性。

四、优缺点

优点:

  1. 节省内存:通过共享对象,减少了大量相似对象的创建,降低了内存消耗。

  2. 提高性能:由于减少了对象的创建次数,特别是对于创建成本高的对象,能显著提升系统性能。

缺点:

  1. 增加系统复杂性:引入享元模式需要额外设计享元池、管理共享对象等,增加了系统的复杂性。

  2. 外部状态管理:外部状态需要由客户端(使用方)负责传递给享元对象,增加了使用难度和复杂性。

五、Java代码示例

以下是一个简单的Java代码示例,模拟一个打印服务,使用享元模式来共享字体对象:

java">import java.util.HashMap;
import java.util.Map;// 抽象享元角色(Flyweight)
interface Font {void print(String text);
}// 具体享元角色(Concrete Flyweight)
class ConcreteFont implements Font {private String fontName;// 内部状态,共享的字体名称public ConcreteFont(String fontName) {this.fontName = fontName;}@Overridepublic void print(String text) {System.out.println("打印文本 '" + text + "' 使用字体 '" + fontName + "'");}
}// 享元工厂角色(Flyweight Factory)
class FontFactory {private static Map<String, Font> fontPool = new HashMap<>();// 创建或获取共享的字体对象public static Font getFont(String fontName) {if (!fontPool.containsKey(fontName)) {fontPool.put(fontName, new ConcreteFont(fontName));}return fontPool.get(fontName);}
}// 客户端代码
public class Client {public static void main(String[] args) {Font boldFont = FontFactory.getFont("Bold");boldFont.print("Hello, World!");Font italicFont = FontFactory.getFont("Italic");italicFont.print("Hello, World!");}
}

六、问题与解决方案

  1. 享元对象过多导致内存占用过高:如果享元对象数量过大,即使每个对象都很小,也可能导致内存占用过高。可以通过设置合理的缓存容量限制、LRU(最近最少使用)淘汰策略等方法来控制享元对象的数量。

  2. 享元对象的线程安全问题:在多线程环境下,享元对象的共享可能会引发竞态条件。可以通过使用线程安全的数据结构(如ConcurrentHashMap)、同步块/方法或无锁数据结构等方式来保证线程安全性。

七、与其他模式的对比

  1. 与单例模式的对比享元模式和单例模式都涉及到对象的复用,但单例模式保证一个类只有一个实例,而享元模式允许多个实例,但通过共享这些实例来达到节省资源的目的。

  2. 与工厂模式的对比享元模式通常会配合工厂模式实现享元对象的创建和管理。工厂模式负责创建对象,而享元模式关注如何复用这些对象以节省资源。

  3. 与代理模式的对比:代理模式主要解决的是在直接访问对象时附加额外的操作,而享元模式关注的是如何通过共享对象来减少内存消耗和提高性能。两者虽有相似之处(如都需要一个中间层来管理对象),但目的和侧重点不同。


http://www.ppmy.cn/ops/16130.html

相关文章

yolo-驾驶行为监测:驾驶分心检测-抽烟打电话检测

在现代交通环境中&#xff0c;随着汽车技术的不断进步和智能驾驶辅助系统的普及&#xff0c;驾驶安全成为了公众关注的焦点之一 。 分心驾驶&#xff0c;尤其是抽烟、打电话等行为&#xff0c;是导致交通事故频发的重要因素。为了解决这一问题&#xff0c;研究人员和工程师们…

多台机器的docker容器的跨主机ROS通信

docker启动时&#xff0c;会在宿主主机上创建一个名为docker0的虚拟网络接口&#xff0c;默认选择172.17.0.0。docker0只是一个在绑定到这上面的其他网卡间自动转发数据包的虚拟以太网桥&#xff0c;它可以使容器和主机相互通信&#xff0c;容器与容器间通信。 问题是&#xf…

竞赛报名赛事管理系统技术分析

竞赛报名赛事管理系统是一个复杂的应用&#xff0c;涉及到用户管理、赛事信息管理、报名管理、成绩管理等多个方面。使用PHP框架来开发这样的系统&#xff0c;可以大大提高开发效率&#xff0c;保证代码的可维护性和可扩展性。以下是对基于PHP框架的竞赛报名赛事管理系统进行功…

2.6设计模式——Flyweight 享元模式(结构型)

意图 运用共享技术有效地支持大量细粒度的对象。 结构 其中 Flyweight描述一个接口&#xff0c;通过这个接口Flyweight可以接受并作用于外部状态。ConcreteFlyweight实现Flyweight接口&#xff0c;并作为内部状态&#xff08;如果有&#xff09;增加存储空间。ConcreteFlywe…

2024考研复试上岸逆袭,机试部分准备

24考研复试机试准备的题目 主要参考书目《王道机试书》《武大历年机试题》 参考代码地址&#xff1a;https://github.com/baizhu0414/CppFiles 另&#xff0c;由于不允许讨论复试题目&#xff0c;因此在此仅提供几点复习建议&#xff1a; 在牛客网做题&#xff0c;里面有很多大…

Parallels Desktop 19完美中文版 PD19虚拟机详细图文安装教程 亲测兼容M1/M2

对于许多Mac用户来说&#xff0c;运行Windows应用程序是必不可少的。也许你的雇主使用的软件只适用于Windows&#xff0c;或者需要使用依赖于某些Windows技术的网站。或者你想在Mac上玩Windows游戏。或者&#xff0c;你可能需要在其他操作系统上测试应用程序和服务——你可以在…

前端路由的实现原理

当谈到前端路由时&#xff0c;指的是在前端应用中管理页面导航和URL的机制。前端路由使得单页应用&#xff08;Single-Page Application&#xff0c;SPA&#xff09;能够在用户与应用交互时动态地加载不同的视图&#xff0c;而无需每次都重新加载整个页面。 在前端开发中&…

Linux的自动化脚本:使用crul命令的从某个网站获取数据(从url获取数据),并将其写入一个文件中

目录 一、要求 二、思路 三、shell脚本实现演练 &#xff08;一&#xff09;脚本实现 &#xff08;二&#xff09;脚本代码说明 &#xff08;三&#xff09;脚本执行 &#xff08;四&#xff09;数据内容 一、要求 Linux的一个进程需要获取一个网站上的最新数据&#xf…