设计模式详解(享元模式)

devtools/2025/2/11 19:16:32/

一、引言

设计模式是一种用于解决在特定上下文中经常出现的问题的优秀解决方案。它们为开发人员提供了一种通用的设计语言,有助于创建灵活且可维护的代码。享元设计模式(Flyweight Pattern)是结构型模式之一,它通过共享对象来减少系统中对象的数量,从而降低系统资源消耗,提高系统性能。

二、享元设计模式的概念

享元设计模式(Flyweight Pattern)是众多设计模式中的一种,它专注于解决由于创建大量相似对象而导致的系统资源消耗过高的问题。这一模式的核心思想是“共享”,即通过共享尽可能多的对象来减少系统中对象的总数,进而降低内存占用和提高系统性能。

1、对象状态的划分
享元模式中,一个关键的概念是将对象的状态划分为两部分:内在状态(Intrinsic State)和外在状态(Extrinsic State)。

内在状态:这是对象内部固有的、不会随环境改变而变化的属性。内在状态通常是可以被共享的,因为它不会因外在条件的不同而有所区别。例如,在一个字符渲染系统中,字符的字体、大小等属性就可以被视为内在状态,因为不论在什么上下文中,相同字体和大小的字符都可以被复用。

外在状态:这是对象在特定上下文中才有的、会随着环境改变而变化的属性。外在状态是不能被共享的,因为它依赖于对象所处的具体环境和上下文。继续以字符渲染为例,字符的位置、颜色等可能因用户交互或页面布局的不同而变化,因此这些属性被视为外在状态。

2、共享机制
享元模式通过实现一个享元工厂(Flyweight Factory)来管理对象的创建和共享。享元工厂会维护一个已创建享元对象的缓存(通常是一个哈希表或其他快速查找数据结构),并根据请求的类型(通常由内在状态决定)来返回相应的对象实例。如果请求的类型在缓存中已存在,则直接返回该实例;如果不存在,则创建一个新的享元对象,将其添加到缓存中,并返回给请求者。

3、提升性能与资源利用率:通过上述共享机制,享元模式能够显著减少系统中相似对象的数量,从而降低内存占用。同时,由于避免了不必要的对象创建和销毁操作,系统的整体性能也会得到提升。这在处理大量相似对象时尤为重要,如文本编辑器中的字符渲染、图形界面中的图形元素绘制等场景。

三、享元设计模式的组成

1、Flyweight(享元):这是享元对象,它封装了可以被共享的状态,并且可以被高效地复用。

2、FlyweightFactory(享元工厂):这个工厂负责创建和管理享元对象。它通常会缓存已创建的享元对象,并在请求相同类型的享元时返回已有的实例。

3、Client(客户端):客户端代码使用享元工厂来获取享元对象,并在需要时将其外在状态传递给享元。

四、享元设计模式的工作原理

享元模式的核心思想是“共享”。当系统中需要创建大量相似对象时,享元模式通过以下步骤来优化对象的创建和使用:

1、提取共享状态:首先,识别出对象中可以共享的状态,并将其封装在享元类中。

2、分离变化状态:将不能共享或随上下文变化的状态从享元类中分离出来,作为外在状态。

3、创建享元工厂:实现一个享元工厂来管理享元对象的创建和缓存。当客户端请求一个新的享元时,工厂首先检查缓存中是否已经存在相同类型的享元。如果存在,则返回该实例;否则,创建一个新的享元实例并添加到缓存中。

4、客户端使用:客户端代码通过享元工厂获取享元对象,并根据需要设置其外在状态。享元对象在执行操作时,会结合其内在状态和传递进来的外在状态来完成任务。

五、享元模式的使用

享元模式的实现通常涉及到一个享元类(表示要共享的对象),一个享元工厂类(负责创建和管理享元实例),以及客户端代码。下面代码展示如何使用享元模式来减少具有相同属性的对象的数量。

首先,定义享元类 Circle,表示一个圆形对象,其内在状态是颜色,这里假设所有圆的大小相同,因此不需要作为内在状态。

java">public class Circle {private String color; // 内在状态:颜色public Circle(String color) {this.color = color;}public String getColor() {return color;}// 假设的绘制方法,这里仅打印信息public void draw() {System.out.println("绘制一个颜色为 " + color + " 的圆形");}
}

然后,定义享元工厂类 CircleFactory,它负责管理并缓存已经创建的 Circle 对象。

java">import java.util.HashMap;
import java.util.Map;public class CircleFactory {private Map<String, Circle> circleMap = new HashMap<>(); // 用于缓存Circle对象的Map// 根据颜色获取Circle对象,如果缓存中没有则创建一个public Circle getCircle(String color) {Circle circle = circleMap.get(color);if (circle == null) {circle = new Circle(color);circleMap.put(color, circle); // 将新创建的Circle对象加入缓存}return circle;}

}
最后,编写客户端代码来使用享元工厂创建和使用享元对象。

java">public class FlyweightPatternDemo {private static final CircleFactory circleFactory = new CircleFactory();public static void main(String[] args) {// 从享元工厂获取圆形对象,并绘制它们Circle circle1 = circleFactory.getCircle("红色");circle1.draw(); // 输出:绘制一个颜色为 红色的圆形Circle circle2 = circleFactory.getCircle("蓝色");circle2.draw(); // 输出:绘制一个颜色为 蓝色的圆形Circle circle3 = circleFactory.getCircle("红色");circle3.draw(); // 输出:绘制一个颜色为 红色的圆形(注意这里是复用的circle1)// 验证circle1和circle3是否是同一个对象System.out.println(circle1 == circle3); // 输出:true}
}

Circle 类是享元,它的内在状态是颜色。CircleFactory 是一个享元工厂,它使用一个 HashMap 来缓存已经创建的 Circle 对象。当客户端请求一个具有特定颜色的圆形时,享元工厂首先检查缓存中是否已经有一个具有该颜色的圆形。如果有,则返回该对象;否则,创建一个新的 Circle 对象并将其添加到缓存中。通过这种方式,具有相同颜色的圆形对象实例在系统中只会被创建一次,从而减少了内存占用。

六、享元设计模式的优点和适用场景

优点:

  • 减少内存消耗:通过共享对象实例,减少了系统中对象的数量,从而降低了内存消耗。

  • 提高性能:避免了频繁的对象创建和销毁操作,提高了系统的运行性能。

  • 简化系统设计:享元模式有助于将对象的共享部分和变化部分分离开来,使系统设计更加清晰和灵活。

适用场景:

  • 当系统中需要处理大量相似对象时,如字符串、图形对象等。

  • 当对象的创建成本较高,且大量对象之间存在大量重复数据时。

  • 当需要优化系统资源消耗和提高系统性能时。

结语
享元设计模式是一种高效处理大量相似对象的设计方案。它通过共享对象实例来减少资源消耗和提高性能,适用于多种场景。在使用享元模式时,需要仔细识别对象的共享状态和变化状态,并合理设计享元类和享元工厂。


http://www.ppmy.cn/devtools/158005.html

相关文章

MHTML文件如何在前端页面展示

MHTML文件如何在前端页面展示 需求背景&#xff1a; 目前在给证券公司做项目&#xff0c;但是在使用新系统的过程中&#xff0c;甲方还希望之前之前系统的历史记录可以看到。 最初制定的计划是项目组里面做数据的把原系统页面爬取下来&#xff0c;转成图片&#xff0c;直接给…

安装 Ollama 需要哪些步骤?(windows+mac+linux+二进制+Docker)

安装 Ollama 的步骤根据操作系统不同会有所差异,以下是针对不同操作系统的详细安装指南: Windows 系统 下载安装包:访问 Ollama 官方下载页面,下载适用于 Windows 的安装程序 OllamaSetup.exe。运行安装程序:双击下载的安装包,按照提示完成安装。默认安装路径为 C:\User…

Dockerfile中Alpine镜像设置东八时区

RUN apk add tzdata # 设置时区为东八区&#xff08;上海&#xff09; RUN ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime参考 Setting the timezone

【SpringBoot】单元测试实战演示及心得分享

目录 1.指定测试标准 2.设计测试用例 3.测试集示例 4.跑测试集 1.指定测试标准 单元测试会用到mock和junit的内容&#xff0c;作者前文有详解&#xff0c;可移步&#xff1a; Spring Boot单元测试-CSDN博客 mockito的详细使用-CSDN博客 1.1.测哪一层&#xff1f; 以当…

APP广告变现如何优化广告填充率,提升变现收益?

APP广告变现对接聚合广告平台可以提升广告变现效率&#xff0c;最大化广告收益。#APP广告变现# 一般来说&#xff0c;广告填充率越高&#xff0c;意味着广告采买方数量越多&#xff0c;可以将广告库存卖掉。但实际的广告变现业务中&#xff0c;100%的广告填充率几乎无法达成。…

微软编程之C#如何学习,C#学习路线:从入门到精通

引言 C# 是一种由微软开发的面向对象编程语言&#xff0c;广泛应用于 Windows 应用程序开发、游戏开发&#xff08;Unity&#xff09;、Web 开发&#xff08;ASP.NET&#xff09;等领域。对于初学者来说&#xff0c;掌握 C# 不仅能够打开编程世界的大门&#xff0c;还能为未来…

基于Ubuntu Ollama 部署 DeepSeek-R132B 聊天大模型(附带流式接口调用示例)

最近 DeepSeek出来了&#xff0c;很火&#xff0c;说是能跟ChatGpt o1 媲美&#xff0c;结果&#xff0c;用了DeepSeek的官方服务&#xff0c;提示“服务器繁忙 请稍后再试。”&#xff0c;我就想&#xff0c;算了&#xff0c;自己部署个吧。 我这个是基于docker部署的&#x…

深入理解QT的View-Model-Delegate机制和用法

文章目录 Model-View-Delegate机制Model(数据模型)设置模型属性访问元素操作元素数据排序封装好的模型View(视图)显示数据数据选择Delegate(代理)数据选择易用封装类QListWidgetQTreeWidgetQTableWidget元素拖拽代理模型参考示例Model-View-Delegate机制 Qt的View/Model/Deleg…