当前位置: 首页 > news >正文

设计模式14-享元模式

设计模式14-享元模式

  • 由来动机
  • 定义与结构
  • 代码推导
  • 特点
  • 享元模式的应用
  • 总结
    • 优点
    • 缺点
    • 使用享元模式的注意事项

由来动机

在很多应用中,可能会创建大量相似对象,例如在文字处理器中每个字符对象。在这些场景下,如果每个对象都独立存在,将会导致巨大的内存开销。那么如何在避免大量颗粒度对象问题的同时,让外部客户程序仍然能够透明的使用面向对象的方式来进行操作呢?享元模式的主要动机是通过共享相似对象来减少内存使用,提高系统性能,来解决此类问题。

享元模式适用于以下情况:

  • 应用程序使用大量相同或相似对象。
  • 对象的大部分状态可以外部化,从而使得许多对象能够共享同一个实例。
  • 需要支持大量细粒度对象高效地共享和复用。

定义与结构

模式定义: 运用共享技术有效地支持大量细粒度的对象。–《设计模式》GoF

享元模式由以下几个主要角色组成:

  1. Flyweight(享元接口): 定义了对象的接口,可以接受外部状态。
  2. ConcreteFlyweight(具体享元): 实现Flyweight接口,并为内部状态(不变部分)进行存储。
  3. UnsharedConcreteFlyweight(非共享享元): 并不是所有的Flyweight子类都需要被共享,非共享Flyweight类可以实现Flyweight接口,但它们不是共享的。
  4. FlyweightFactory(享元工厂): 创建并管理Flyweight对象,确保合理地共享Flyweight。

以下是享元模式的UML图:
在这里插入图片描述

代码推导

下面我们通过C++代码示例来实现享元模式。

  1. 定义Flyweight接口:
class Flyweight {
public:virtual void operation(int extrinsicState) = 0;virtual ~Flyweight() = default;
};
  1. 实现具体享元类:
#include <iostream>class ConcreteFlyweight : public Flyweight {
private:int intrinsicState;public:ConcreteFlyweight(int state) : intrinsicState(state) {}void operation(int extrinsicState) override {std::cout << "Intrinsic State: " << intrinsicState << ", Extrinsic State: " << extrinsicState << std::endl;}
};
  1. 实现享元工厂类:
#include <unordered_map>
#include <memory>class FlyweightFactory {
private:std::unordered_map<int, std::shared_ptr<Flyweight>> flyweights;public:std::shared_ptr<Flyweight> getFlyweight(int key) {if (flyweights.find(key) == flyweights.end()) {flyweights[key] = std::make_shared<ConcreteFlyweight>(key);}return flyweights[key];}
};
  1. 使用享元模式:
int main() {FlyweightFactory factory;std::shared_ptr<Flyweight> fw1 = factory.getFlyweight(1);std::shared_ptr<Flyweight> fw2 = factory.getFlyweight(2);std::shared_ptr<Flyweight> fw3 = factory.getFlyweight(1); // Reuses the existing Flyweightfw1->operation(10);fw2->operation(20);fw3->operation(30);return 0;
}

特点

  1. 共享对象: 通过共享细粒度对象,减少内存使用,提高性能。
  2. 内部状态和外部状态: 将对象的状态分为内部状态和外部状态,内部状态存储在享元对象中,而外部状态由客户端传入。
  3. 不可变性: 享元对象是不可变的,确保共享时不会被其他对象修改。
  4. 工厂管理: 使用享元工厂管理享元对象的创建和共享,确保唯一实例。

享元模式的应用

享元模式在以下场景中非常有用:

  1. 文本处理: 文本编辑器中,每个字符都是一个对象,通过享元模式共享字符对象,减少内存消耗。
  2. 图形系统: 在图形系统中,大量相似的图形对象可以通过享元模式共享,例如树木、建筑物等。
  3. 缓存: 使用享元模式实现对象缓存,避免重复创建相同的对象。
  4. 游戏开发: 在游戏开发中,使用享元模式共享相同类型的游戏对象,例如敌人、子弹等,减少内存使用。

总结

  • 面对对象很好的解决了抽象性的问题,但是作为一个运行在机器中的程序实体我们需要考虑对象的代价问题。享元模式主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。
  • 享元模式采用对象共享的方法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实践方面要注意对象状态的处理。
  • 对象的数量太大,从而导致对象内存开销加大,什么样的数量才算大?这需要我们仔细的根据具体应用情况进行评估,而不能评空臆断。

优点

  1. 减少内存消耗: 通过共享细粒度对象,享元模式大大减少了内存的使用。当有大量相似对象需要创建时,享元模式特别有效。
  2. 提升性能: 由于减少了内存使用,享元模式可以提升系统的性能,特别是在内存有限或系统资源紧张的情况下。
  3. 分离内部状态和外部状态: 享元模式将对象的状态分为内部状态(共享部分)和外部状态(非共享部分),使得对象更加轻量化。

缺点

  1. 复杂性增加: 享元模式引入了额外的复杂性,特别是在处理对象状态时,需要明确区分内部状态和外部状态。
  2. 维护困难: 享元模式需要维护一个共享对象的池,这增加了代码的复杂性和维护难度。
  3. 线程安全问题: 在多线程环境下,需要确保享元对象的线程安全性,可能需要引入额外的同步机制,影响性能。

使用享元模式的注意事项

  1. 区分内部状态和外部状态: 在使用享元模式时,需要明确区分哪些状态可以共享(内部状态),哪些状态是对象独有的(外部状态)。
  2. 适用场景: 享元模式适用于有大量相似对象的场景,例如图形系统、文本处理、游戏开发等。如果对象数量不多,或者对象之间差异较大,使用享元模式的意义不大。
  3. 线程安全: 在多线程环境下,共享的享元对象需要是线程安全的。可以使用锁(例如std::mutex)或者其他同步机制确保线程安全。
  4. 内存泄漏: 享元模式中的享元工厂负责管理共享对象,需要确保及时释放不再使用的共享对象,以避免内存泄漏。
  5. 性能权衡: 虽然享元模式可以减少内存使用,但也会引入一些性能开销,例如对象池的维护、同步机制的使用等。在设计时需要权衡这些开销。

相关文章:

设计模式14-享元模式

设计模式14-享元模式 由来动机定义与结构代码推导特点享元模式的应用总结优点缺点使用享元模式的注意事项 由来动机 在很多应用中&#xff0c;可能会创建大量相似对象&#xff0c;例如在文字处理器中每个字符对象。在这些场景下&#xff0c;如果每个对象都独立存在&#xff0c…...

Javascript中canvas与svg详解

Canvas 在JavaScript中&#xff0c;<canvas> 元素用于在网页上绘制图形&#xff0c;如线条、圆形、矩形、图像等。它是一个通过JavaScript和HTML的<canvas>元素来工作的绘图表面。<canvas> 元素自身并不具备绘图能力&#xff0c;它仅仅提供了一个绘图环境&a…...

【BUG】已解决:No Python at ‘C:Users…Python Python39python. exe’

No Python at ‘C:Users…Python Python39python. exe’ 目录 No Python at ‘C:Users…Python Python39python. exe’ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班…...

Flink SQL 的工作机制

前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出&#xff0c;一段查询 SQL / 使用TableAPI 编写的程序&#xff08;以下简称 TableAPI 代码&#xff09;从输入到编译为可执行的 JobGraph 主要经历如下几个阶段&#xff1a; 将 SQL文本 / TableAPI 代码转化为逻辑执…...

[AI Mem0] 源码解读,带你了解 Mem0 的实现

Mem0 的 CRUD 到底是如何实现的&#xff1f;我们来看下源码。 使用 先来看下&#xff0c;如何使用 Mem0 import os os.environ["OPENAI_API_KEY"] "sk-xxx"from mem0 import Memorym Memory()# 1. Add: Store a memory from any unstructured text re…...

【LLM】-10-部署llama-3-chinese-8b-instruct-v3 大模型

目录 1、模型下载 2、下载项目代码 3、启动模型 4、模型调用 4.1、completion接口 4.2、聊天&#xff08;chat completion&#xff09; 4.3、多轮对话 4.4、文本嵌入向量 5、Java代码实现调用 由于在【LLM】-09-搭建问答系统-对输入Prompt检查-CSDN博客 关于提示词注入…...

C语言 之 理解指针(4)

文章目录 1. 字符指针变量2. 数组指针变量2.1 对数组指针变量的理解2.2 数组指针变量的初始化 3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用 5. 函数指针数组 1. 字符指针变量 我们在前面使用的主要是整形指针变量&#xff0c;现在要学…...

Java设计模式—单例模式(Singleton Pattern)

目录 一、定义 二、应用场景 三、具体实现 示例一 示例二 四、懒汉与饿汉 饿汉模式 懒汉模式 五、总结 六、说明 一、定义 二、应用场景 ‌单例模式的应用场景主要包括以下几个方面&#xff1a; ‌日志系统&#xff1a;在应用程序中&#xff0c;通常只需要一个日…...

AV1帧间预测(二):运动补偿

运动补偿(Motion Compensation,MC)是帧间预测最基础的工具&#xff0c;AV1支持两种运动补偿方式&#xff0c;一种是传统的平移运动补偿&#xff0c;另一种是仿射运动补偿。下面分别介绍这两种运动补偿方法。 平移运动补偿 平移运动补偿是最传统的运动补偿方式&#xff0c;H.26…...

数学建模(5)——逻辑回归

一、二分类 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklea…...

【C++高阶】:深入探索C++11

✨ 心似白云常自在&#xff0c;意如流水任东西 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;C学习 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f4…...

6. 自定义Docker镜像

如何自定义Docker镜像&#xff1a;从基础到实践 Docker作为一个容器化平台&#xff0c;使得应用的打包、分发和运行变得更加高效和便捷。本文将详细介绍如何自定义一个Docker镜像&#xff0c;包括镜像的构成、分层原理、创建自定义镜像的具体步骤&#xff0c;并演示如何打包和…...

「12月·长沙」人工智能与网络安全国际学术会议(ISAICS 2024)

人工智能与网络安全国际学术会议(ISAICS 2024)将于2024年12月20日-2024年12月22日在湖南长沙召开。会议中发表的文章将会被收录,并于见刊后提交EI核心索引。会议旨在在为国内与国际学者搭建交流平台,推进不同学科领域的融合发展&#xff0c;就当今人工智能与网络安全范畴内各学…...

【技术支持案例】使用S32K144+NSD8381驱动电子膨胀阀

文章目录 1. 前言2. 问题描述3. 理论分析3.1 NSD8381如何连接电机3.2 S32K144和NSD8381的软件配置 4.测试验证4.1 测试环境4.2 测试效果4.3 测试记录 1. 前言 最近有客户在使用S32K144NSD8381驱动电子膨胀阀时&#xff0c;遇到无法正常驱动电子膨胀阀的情况。因为笔者也是刚开…...

第二期:集成电路(IC)——智能世界的微观建筑大师

嘿&#xff0c;小伙伴们&#xff01;&#x1f44b; 我是你们的老朋友小竹笋&#xff0c;一名热爱创作和技术的工程师。上一期我们聊了聊AI芯片&#xff0c;这次我们要深入到更微观的层面&#xff0c;来探究集成电路&#xff08;IC&#xff09;的世界。准备好一起探索了吗&#…...

基于物联网的区块链算力网络,IGP/BGP协议

目录 基于物联网的区块链算力网络 IGP/BGP协议 IGP(内部网关协议) BGP(边界网关协议) 内部使用ISP的外部使用BGP的原因 一、网络规模和复杂性 二、路由协议的特性 三、满足业务需求 四、结论 基于物联网的区块链算力网络 通 过 多个物联网传感器将本地计算…...

每日一题~960 div2 A+B+C(简单奇偶博弈,构造,观察性质算贡献)

A题意&#xff1a; N 长的数组。 一次操作&#xff1a; 最开始的mx 为零。 选出一个数&#xff08;使得这个数>mx) ,之后将mx 更新为这个数&#xff0c;将这个数置为零。 不能做这个操作的&#xff0c;输。 问是否有先手赢的策略。有的话&#xff0c;输出yes 否则no 当时一…...

音视频入门基础:H.264专题(17)——FFmpeg源码获取H.264裸流文件信息(视频压缩编码格式、色彩格式、视频分辨率、帧率)的总流程

音视频入门基础&#xff1a;H.264专题系列文章&#xff1a; 音视频入门基础&#xff1a;H.264专题&#xff08;1&#xff09;——H.264官方文档下载 音视频入门基础&#xff1a;H.264专题&#xff08;2&#xff09;——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…...

Aboboo一些操作

常用快捷键⌨ 快捷键/操作方式 功能 鼠标中键/Esc 进入/退出全屏 空格/Tab 暂停/恢复播放 左/右箭头 快退/快进 Ctrl-左/右箭头 30秒快退/快进 Alt-左/右箭头 60秒快退/快进 Ctrl-Alt-左/右箭头 播放速率调节 PageUp/PageDown 上一句/下一句 上下箭头/滚轮 …...

获取行号LineNumberReader

(每日持续更新&#xff09;jdk api之LineNumberReader基础、应用、实战-CSDN博客...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...