11.享元模式 (Flyweight)

devtools/2025/2/6 13:05:07/

定义

Flyweight 模式(享元模式) 是一种结构型设计模式,它旨在通过共享对象来有效支持大量细粒度对象的复用。该模式主要通过共享细节来减少内存使用,提升性能,尤其在需要大量对象时非常有效。

基本思想:

共享对象:对象的内存资源和属性可以共享,从而减少内存消耗。
外部状态与内部状态的区分:
内部状态:在对象内部存储的属性,通常是共享的,可以被多个对象共享。
外部状态:依赖于具体的上下文环境,通常是每个对象独有的,不共享的。

Flyweight 模式的核心目标是:

  • 共享和复用:将对象的共享部分提取出来,以减少内存消耗。
  • 提高性能:通过避免重复创建大量相似的对象来提升性能。

Flyweight 模式适用于以下场景:

需要大量对象:当一个系统需要大量相似对象时,使用 Flyweight 模式可以减少内存开销。
对象细粒度重复:系统中很多对象的内部状态相同,只有外部状态不同。
资源有限的环境:在内存或者其他资源有限的环境中,Flyweight 可以有效降低资源消耗。
对象状态可分离:可以将对象的状态分为内部状态和外部状态。

常见应用场景:

图形应用:多个相同的图形(如圆形、矩形)共享相同的属性。
文字渲染:不同的字符共享相同的字体样式、大小等。

类设计

Flyweight 模式通常包括以下角色:

Flyweight(享元):定义共享对象的接口。
ConcreteFlyweight(具体享元):实现 Flyweight 接口,存储共享的状态。
FlyweightFactory(享元工厂):管理享元对象池,确保对象复用。
Client(客户端):使用享元对象,区分内部和外部状态。


#include <iostream>
#include <map>
#include <string>
using namespace std;class Font {
private:string key;  // 内部状态:唯一的字体标识符(共享部分)// 其他内部状态(例如字体样式、字体颜色等)public:Font(const string& key) : key(key) {cout << "Font created with key: " << key << endl;}void display(const string& text) {// 外部状态:文本的内容可以不同cout << "Displaying font " << key << " for text: " << text << endl;}
};class FontFactory {
private:map<string, Font*> fontPool;  // 享元池:管理字体对象(共享的内部状态)public:Font* GetFont(const string& key) {map<string, Font*>::iterator item = fontPool.find(key);if (item != fontPool.end()) {// 如果享元池中有对应的字体,直接返回cout << "Reusing existing font: " << key << endl;return item->second;} else {// 如果没有对应字体,创建新的字体对象Font* font = new Font(key);fontPool[key] = font;return font;}}void clear() {for (auto& item : fontPool) {delete item.second;}fontPool.clear();}
};int main() {FontFactory fontFactory;// 获取并显示字体Font* font1 = fontFactory.GetFont("Arial");font1->display("Hello World!");Font* font2 = fontFactory.GetFont("Arial");font2->display("Hello again!");Font* font3 = fontFactory.GetFont("Times New Roman");font3->display("New text!");// 享元池重用 "Arial" 字体Font* font4 = fontFactory.GetFont("Arial");font4->display("Reusing Arial");// 清理资源fontFactory.clear();return 0;
}

运行代码后输出如下:

Font created with key: Arial
Displaying font Arial for text: Hello World!
Reusing existing font: Arial
Displaying font Arial for text: Hello again!
Font created with key: Times New Roman
Displaying font Times New Roman for text: New text!
Reusing existing font: Arial
Displaying font Arial for text: Reusing Arial

从输出可以看到:
对于 Arial 字体,第一次调用时创建了字体对象。
第二次获取 Arial 字体时,直接复用了已经创建的对象。
对于 Times New Roman,则是新创建的字体对象。

类设计分析

  1. Font 类(享元类)
    Font 类代表一个字体对象,它有一个 key 属性作为内部状态。这是一个共享的属性。字体对象通过这个 key 来区分不同的字体样式。
    display 方法接受外部状态(例如文本内容),该外部状态每次调用时可能不同,但内部状态(如字体样式)是共享的。
  2. FontFactory 类(享元工厂)
    FontFactory 类是享元模式的核心,它负责管理所有的字体实例(通过 fontPool),并确保字体的复用。
    当请求字体对象时,GetFont 方法首先检查字体池(fontPool)中是否已有对应的字体,如果存在则返回现有实例,否则创建一个新的字体并存储到池中。
    clear 方法清理享元池中的所有对象,防止内存泄漏。
  3. 客户端
    客户端通过 FontFactory 获取字体对象,并调用 display 方法来展示文本。不同的文本内容共享相同的字体对象(即内部状态)。

总结

角色 描述
Font 享元类,存储共享的字体内部状态。
FontFactory 享元工厂,管理字体实例的池并保证字体复用。
Client 客户端,使用 FontFactory 获取字体并设置外部状态。
Flyweight 模式的优点:
节省内存:多个相同对象共享相同的内部状态,只存储一份,减少内存占用。
提高性能:通过复用相同的对象来减少对象创建的开销。
减少垃圾回收负担:复用对象减少了不必要的对象创建和销毁。
Flyweight 模式的缺点:
外部状态管理复杂:需要在客户端管理外部状态,将外部状态传递给享元对象。
实现复杂度:需要设计享元池和管理对象的共享方式,代码复杂度增加。

适用场景

游戏开发:需要大量相同的图形对象,如背景、敌人等。
文本处理:需要处理大量字符、字体、样式的渲染。
图形渲染:需要共享形状、颜色等属性的图形对象。
网络请求:不同请求使用相同的网络连接池。

总结

Flyweight 模式通过对象的共享来有效减少内存消耗,适用于需要大量相似对象的场景。它通过将对象的内部状态与外部状态区分,并只共享内部状态,从而提高了系统的效率。


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

相关文章

【LeetCode 刷题】回溯算法(5)-棋盘问题

此博客为《代码随想录》二叉树章节的学习笔记&#xff0c;主要内容为回溯算法棋盘问题相关的题目解析。 文章目录 51. N皇后37. 解数独332.重新安排行程 51. N皇后 题目链接 class Solution:def solveNQueens(self, n: int) -> List[List[str]]:board [[. for _ in rang…

http和https的区别?

文章目录 一、安全性二、连接方式三、端口使用四、证书申请五、优缺点六、SSL&TLS协议6.1、SSL协议6.2、TLS协议6.3、SSL/TLS协议在HTTPS中的应用 总结 HTTP和HTTPS是两种常见的网络传输协议&#xff0c;它们在安全性、连接方式、端口使用以及证书申请等方面存在显著差异。…

【C语言】指针详细解读3

1. 数组名的理解 我们使用指针一般访问数组内容时&#xff0c;我们可能会这样写&#xff1a; int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0]; 这⾥我们使⽤ &arr[0] 的⽅式拿到了数组第⼀个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;⽽…

React常见状态管理工具详解

了 解React常见的状态管理工具&#xff0c;需要详细解释。首先&#xff0c;我得回想一下React生态中常用的状态管理方案有哪些。React本身有useState和useContext&#xff0c;然后是第三方库比如Redux、MobX、Recoil、Zustand、Jotai、XState&#xff0c;可能还有Valtio。这些工…

Hackmyvm Deeper

简介 难度&#xff1a;简单 靶机&#xff1a;https://hackmyvm.eu/machines/?vdeeper 基本信息 kali&#xff1a;192.168.194.9 靶机&#xff1a;192.168.194.20 扫描 nmap基操 tcp扫描起手&#xff0c;nmap -sT -sV -A -T4 192.168.194.20 -Pn -p- 开启的tcp端口只有ss…

DeepSeek大模型介绍、本地化部署与使用!【AI大模型】

一、DeepSeek 是什么&#xff1f; 1.技术定位 专注大模型与AGI研究&#xff0c;开发高性能基座模型&#xff08;如 DeepSeek LLM 系列&#xff09;&#xff0c;支持长文本、多模态、代码生成等复杂任务。 提供开源模型&#xff08;如 DeepSeek-MoE、DeepSeek-V2&#xff09;…

Web - CSS3浮动定位与背景样式

概述 这篇文章主要介绍了 CSS3 中的浮动定位、背景样式、变形效果等内容。包括 BFC 规范与创建方法、浮动的功能与使用要点、定位的多种方式及特点、边框与圆角的设置、背景的颜色、图片等属性、多种变形效果及 3D 旋转等&#xff0c;还提到了浏览器私有前缀。 BFC规范与浏览…

Vue Dom截图插件,截图转Base64 html2canvas

安装插件 npm install html2canvas --save插件使用 <template><div style"padding: 10px;"><div ref"imageTofile" class"box">发生什么事了</div><button click"toImage" style"margin: 10px;&quo…