重温设计模式--享元模式

文章目录

      • 享元模式(Flyweight Pattern)概述
      • 享元模式的结构
      • C++ 代码示例1
      • 应用场景
      • C++示例代码2

享元模式(Flyweight Pattern)概述

  1. 定义
    运用共享技术有效地支持大量细粒度的对象。
    享元模式是一种结构型设计模式,它主要用于减少创建对象的数量,以减少内存占用和提高性能。该模式通过共享尽可能多的对象数据来实现这一点,对于那些在系统中会大量重复出现且内部状态可以被共享的对象,将其可共享的部分提取出来,进行统一管理和共享使用,而把那些依赖于具体场景不能共享的部分作为外部状态传入。

  2. 作用

    • 节省内存:在一些应用场景中,比如游戏开发里有大量相似的游戏元素(如相同外观的小兵角色等),如果每个都创建独立的对象,会消耗大量内存。通过享元模式共享这些元素的通用部分,能大大减少内存开销。
    • 提升性能:创建对象是有一定开销的,当大量重复创建相似对象时,会影响系统性能。享元模式避免了不必要的重复创建,使得系统在运行时更加高效,例如在图形绘制系统中,频繁绘制相同图形时,共享图形对象能加快绘制速度。
    • 便于管理对象状态:将对象的状态分为内部状态(可共享的、不随外部环境变化的部分)和外部状态(随具体场景变化的部分),使得对象状态的管理更加清晰和有条理,便于对不同场景下对象的行为进行控制。

享元模式的结构

  1. 抽象享元(Flyweight)
    这是所有具体享元类的抽象,定义了享元对象的公共接口,通常包含可以接收外部状态并执行相应操作的方法等。

  2. 具体享元(Concrete Flyweight)
    实现了抽象享元的接口,它持有内部状态,并且这些内部状态在不同实例间是可以共享的。具体享元对象的内部状态决定了它的固有行为,在创建后通常不会改变(除非有特定的修改逻辑设计)。

  3. 享元工厂(Flyweight Factory)
    负责创建和管理享元对象。它维护一个享元对象的池(通常可以用std::map等容器来实现),在客户端请求创建享元对象时,先检查池中是否已经存在,如果存在就直接返回已有的对象,避免重复创建;如果不存在,则创建一个新的具体享元对象并放入池中,然后返回给客户端。

  4. 客户端(Client)
    客户端是使用享元对象的地方,它需要维护享元对象的外部状态,并且通过享元对象的接口,传入外部状态来调用相应的操作,完成业务逻辑。

在这里插入图片描述

C++ 代码示例1

以下以一个简单的图形绘制系统为例,假设有多种颜色的圆形需要绘制,颜色是可以共享的内部状态(因为可能有多个圆形都是同一种颜色),而圆形的坐标位置是外部状态(每个圆形在不同位置绘制)。

#include <iostream>
#include <map>
#include <string>// 抽象享元类
class Shape
{
public:virtual void draw(int x, int y) = 0;virtual ~Shape() {}
};// 具体享元类 - 圆形
class Circle : public Shape
{
private:std::string color;
public:Circle(std::string col) : color(col) {}void draw(int x, int y) override {std::cout << "在坐标(" << x << ", " << y << ")绘制了一个" << color << "的圆形" << std::endl;}
};// 享元工厂类
class ShapeFactory
{
private:std::map<std::string, Shape*> shapeMap;
public:Shape* getShape(std::string color) {if (shapeMap.find(color) == shapeMap.end()) {shapeMap[color] = new Circle(color);}return shapeMap[color];}~ShapeFactory(){for (auto it = shapeMap.begin(); it!= shapeMap.end(); ++it){delete it->second;}}
};// 客户端代码
int main()
{ShapeFactory factory;Shape* circle1 = factory.getShape("红色");Shape* circle2 = factory.getShape("红色");Shape* circle3 = factory.getShape("蓝色");circle1->draw(10, 20);circle2->draw(30, 40);circle3->draw(50, 60);return 0;
}

在上述代码中:

  • Shape是抽象享元类,定义了draw方法作为所有图形绘制的统一接口,这里只考虑简单的绘制操作示例,传入坐标参数来表示绘制的位置。

  • Circle是具体享元类,它有一个表示颜色的私有成员变量color作为内部状态,实现了draw方法,根据传入的坐标在相应位置绘制指定颜色的圆形。

  • ShapeFactory是享元工厂类,内部用std::map容器维护了一个形状对象的映射表,getShape方法根据传入的颜色参数来查找是否已经创建过对应的圆形对象,如果没有则创建一个新的Circle对象并放入映射表中,然后返回对应的形状对象,这样就实现了相同颜色的圆形对象的共享,避免重复创建。在其析构函数中,对创建的所有形状对象进行内存释放,防止内存泄漏。

  • main函数作为客户端代码部分,首先创建了享元工厂对象,然后通过工厂获取不同颜色的圆形对象(这里获取了两个红色的圆形和一个蓝色的圆形,其中两个红色圆形其实是共享同一个对象实例),最后分别传入不同的坐标调用draw方法来模拟绘制圆形的操作,展示了享元模式如何在图形绘制场景中通过共享对象来节省内存和管理相似对象的情况。

这个代码示例在VS2010环境下可以正常编译运行,实现了享元模式的基本功能应用,你可以根据实际需求进一步扩展和完善,比如添加更多的图形种类、更复杂的状态管理等内容。

应用场景

  1. 游戏开发
    • 游戏中存在大量重复的游戏元素,比如相同外观的怪物、建筑等。以怪物为例,它们可能具有相同的外观(纹理、模型等可共享的内部状态),只是在游戏地图中的位置(外部状态)不同。通过享元模式,可以让多个相同外观的怪物共享同一个代表外观的对象实例,减少内存占用,同时方便对怪物外观等共享属性进行统一管理和修改。
    • 游戏道具也是如此,很多道具可能有相同的基础样式,但使用时的位置、状态等不同,利用享元模式能优化道具对象的创建和管理。
  2. 图形绘制与可视化系统
    • 在绘制复杂图形界面或者可视化数据展示时,会有大量重复的图形元素,比如绘制地图上的多个相同图标(如代表医院、学校等的图标),这些图标本身的样式(颜色、形状等内部状态)可以共享,只是绘制的坐标位置(外部状态)不一样。享元模式可确保相同样式的图标只创建一次,提升绘制效率并节省内存,方便对图标样式进行统一更新维护。
    • 对于绘制统计图表中的相同类型的图形标记(如柱状图中的柱子样式等),也可以应用享元模式进行优化。
  3. 文本处理与编辑系统
    • 在文字处理软件中,对于字体样式对象,字体的名称、字号、加粗、倾斜等属性是固定的(内部状态),可以共享。而每个文字在文档中的具体位置(外部状态)不同。通过享元模式管理字体样式对象,能避免为每个文字都创建重复的字体样式实例,提高内存利用效率,并且方便对字体样式进行整体的修改和统一管理,比如改变文档中所有某字号字体的颜色等操作。
    • 同样,对于文档中的一些固定格式的段落样式等也可以采用享元模式来优化对象管理,减少内存开销。
  4. 网站开发中的资源管理
    • 网页上经常会有很多重复的图片、图标等资源展示,比如电商网站商品列表中相同类别的商品图片(可能只是商品编号等不同,但图片外观一样),可以把图片资源作为享元对象进行管理,共享相同的图片实例,减少浏览器内存占用,加快网页加载速度,同时便于对图片资源进行更新替换等操作。
    • 网站的一些通用样式组件(如按钮样式、导航栏样式等)也可利用享元模式,将样式相关的内部状态共享,根据页面不同位置等外部状态进行展示和交互,优化网站前端资源的管理和性能。

C++示例代码2

#include<iostream>
#include<list>
#include<string>
#include<vector>
using namespace std;
enum COLOR{RED , BLACK};
//记录名字和坐标
typedef struct NODE
{int x;int y;string name;
}NODE;class PIECE
{
private:COLOR m_color;
public:PIECE(COLOR p_color):m_color(p_color){}~PIECE(){}virtual void  DRAW(){}};class REDPIECE:public PIECE
{
public:REDPIECE(COLOR p_color):PIECE(p_color){}virtual void  DRAW(){cout<<"绘制一颗红棋子"<<endl;}
};class BLACKPIECE:public PIECE
{
public:BLACKPIECE(COLOR p_color):PIECE(p_color){}virtual void  DRAW(){cout<<"绘制一颗黑棋子"<<endl;}
};//棋盘
class BOARD
{
private:list<NODE> m_ls;PIECE*m_redpiece;PIECE*m_blackpiece;
public:BOARD(){m_redpiece=NULL;m_blackpiece=NULL;}~BOARD(){delete m_blackpiece;delete m_redpiece;}void SetPiece(COLOR p_color , NODE p_node){if(p_color==RED){if(m_redpiece == NULL)  //有点单例模式的意思{m_redpiece = new REDPIECE(p_color);	}cout<<p_node.name<<"在位置("<<p_node.x<<','<<p_node.y<<")";m_redpiece->DRAW();}else{if(m_redpiece == NULL)  //有点单例模式的意思{m_redpiece = new REDPIECE(p_color);	}cout<<p_node.name<<"在位置("<<p_node.x<<','<<p_node.y<<")";m_redpiece->DRAW();}m_ls.push_back(p_node);//这里只存放NODE的信息 ,不用存对象的信息,将会大大减少存储空间的消耗}};int main()
{BOARD *m_board= new BOARD();NODE p1;p1.name = "马";p1.x=1;p1.y = 2;NODE p2;p2.name = "车";p2.x=1;p2.y = 2;REDPIECE *m_red = new REDPIECE(RED);m_board->SetPiece(RED , p1);BLACKPIECE *m_black = new BLACKPIECE(BLACK);m_board->SetPiece(BLACK , p2);return 0;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/64974.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用python ollama qwen2.5 开发一个AI修仙游戏

用 Python Ollama (Qwen2.5) 开发一个 AI 修仙游戏 简介 本文将介绍如何使用 Python 和 Ollama (Qwen2.5 模型) 开发一个文字版修仙游戏。这个游戏具有以下特点&#xff1a; 完整的修仙世界观和成长体系基于 AI 生成的动态剧情和事件丰富的物品系统(功法、丹药、灵宝等)社交…

【网络安全】网站常见安全漏洞—服务端漏洞介绍

文章目录 网站常见安全漏洞—服务端漏洞介绍引言1. 第三方组件漏洞什么是第三方组件漏洞&#xff1f;如何防范&#xff1f; 2. SQL 注入什么是SQL注入&#xff1f;如何防范&#xff1f; 3. 命令执行漏洞什么是命令执行漏洞&#xff1f;如何防范&#xff1f; 4. 越权漏洞什么是越…

Linux驱动开发 IIC I2C驱动 编写APP访问EEPROM AT24C02

在嵌入式开发中&#xff0c;I2C&#xff08;Inter-Integrated Circuit&#xff09;是一种常用的串行通信协议&#xff0c;广泛应用于与外设&#xff08;如 EEPROM、传感器、显示屏等&#xff09;进行数据交换。AT24C02 是一种常见的 I2C EEPROM 存储器&#xff0c;它提供 2Kbit…

HDR视频技术之十一:HEVCH.265 的 HDR 编码方案

前文我们对 HEVC 的 HDR 编码优化技术做了介绍&#xff0c;侧重编码性能的提升。 本章主要阐述 HEVC 中 HDR/WCG 相关的整体编码方案&#xff0c; 包括不同应用场景下的 HEVC 扩展编码技术。 1 背景 HDR 信号一般意味着使用更多比特&#xff0c;一般的 HDR 信号倾向于使用 10…

linux普通用户使用sudo不需要输密码

1.root用户如果没有密码&#xff0c;先给root用户设置密码 sudo passwd root #设置密码 2.修改visudo配置 su #切换到root用户下 sudo visudo #修改visudo配置文件 用户名 ALL(ALL) NOPASSWD: ALL #下图所示处新增一行配置 用户名需要输入自己当前主机的用户名

【时间之外】IT人求职和创业应知【74】-运维机器人

目录 OpenAI最强推理模型o3发布&#xff0c;AGI测试能力暴涨 英伟达宣布收购以色列AI初创企业Runai 汤姆猫首款AI机器人产品明日发售 心勿贪&#xff0c;贵知足。 感谢所有打开这个页面的朋友。人生不如意&#xff0c;开越野车去撒野&#xff0c;会害了自己&#xff0c;不如…

C#调用WebService的方法

一、前言 在日常工作中&#xff0c;如果涉及到与第三方进行接口对接&#xff0c;有的会使用WebService的方式&#xff0c;这篇文章主要讲解在.NET Framework中如何调用WebService。 1.创建WebService &#xff08;1&#xff09;新建项目——模板选择ASP.NET Web 应用程序 &a…

Qt creator ,语言家功能缺失解决方法

1、找到工具->外部->配置 2、添加目录&#xff0c;双击命名语言家 3、在语言家目录下&#xff0c;添加工具 双击重命名lupdate&#xff0c;即更新翻译 %{CurrentDocument:Project:QT_INSTALL_BINS}\lupdate%{CurrentDocument:Project:FilePath}%{CurrentDocument:Projec…

Taro小程序开发性能优化实践

我们团队在利用Taro进行秒送频道小程序的同时&#xff0c;一直在探索性能优化的最佳实践。随着需求的不断迭代&#xff0c;项目中的性能问题难免日积月累&#xff0c;逐渐暴露出来影响用户体验。适逢双十一大促&#xff0c;我们趁着这个机会统一进行了Taro性能优化实践&#xf…

springboot471基于协同过滤算法商品推荐系统(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装协同过滤算法商品推荐系统软件来发挥其高效地信息处理的作用…

进程间关系与守护进程

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 进程间关系与守护进程 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 进程组 什…

【NLP 16、实践 ③ 找出特定字符在字符串中的位置】

看着父亲苍老的白发和渐渐老态的面容 希望时间再慢一些 —— 24.12.19 一、定义模型 1.初始化模型 ① 初始化父类 super(TorchModel, self).__init__()&#xff1a; 调用父类 nn.Module 的初始化方法&#xff0c;确保模型能够正确初始化。 ② 创建嵌入层 self.embedding n…

javaEE-多线程编程-3

目录 java 常见的包 : 回调函数: 什么是线程: 第一个线程: 验证多线程执行: 内核: 调用sleep()方法: 执行结果分析: 线程创建的几种方式: 1.继承Thread类,重写run()方法. 2.实现Runnable接口,重写run()方法. 3.继承Thread类,重写run()方法.但使用匿名内部类 4.实现…

怎么在idea中创建springboot项目

最近想系统学习下springboot&#xff0c;尝试一下全栈路线 从零开始&#xff0c;下面将叙述下如何创建项目 环境 首先确保自己环境没问题 jdkMavenidea 创建springboot项目 1.打开idea&#xff0c;选择file->New->Project 2.选择Spring Initializr->设置JDK->…

设计模式期末复习

一、设计模式的概念以及分类 是一套被反复使用&#xff0c;多数人知晓&#xff0c;经过分类编目&#xff0c;代码设计经验的总结&#xff0c;描述了在软件设计的过程中不断重复发生的问题&#xff0c;以及该问题的解决方案&#xff0c;他是解决特定问题的一系列套路&#xff0c…

Github——网页版上传文件夹

第一步&#xff1a;创建一个新的仓库或进入已存在的仓库页面 第二步&#xff1a;点进对应的文件夹下&#xff0c;然后 点击 “Upload files” 第三步&#xff1a;将文件夹拖拽到上传区域 打开资源管理器&#xff0c;将要上传的文件夹从计算机中拖拽到上传区域。 注意&#xf…

高级的SQL查询技巧有哪些?

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于高级SQL查询技巧方面的相关内容&#xf…

FastStone 10.x 注册码

简介 FastStone Capture是一款经典好用的屏幕截图软件&#xff0c;在屏幕截图领域具有广泛的应用和众多优势。 软件基本信息 FastStone Capture体积小巧&#xff0c;占用内存少&#xff0c;这使得它在运行时不会给计算机系统带来过多的负担&#xff0c;即使在配置较低的电脑…

K8S详解(5万字详细教程)

目录 ​编辑 一、集群管理命令 二、命名空间 1. 获取命名空间列表 2. 创建命名空间 3. 删除命名空间 4. 查看命名空间详情 三、Pod 1. Pod概述 2. Pod相位状态 3. 管理命令 3.1 获取命名空间下容器(pod)列表 3.2 查看pod的详细信息 3.3 创建 && 运行 3.4 …

费舍尔信息矩阵全面讲述

费舍尔信息矩阵&#xff08;Fisher Information Matrix&#xff09; 费舍尔信息矩阵是统计学中一个非常重要的概念&#xff0c;尤其在参数估计、最大似然估计&#xff08;MLE&#xff09;和贝叶斯推断中具有广泛的应用。它反映了参数估计的不确定性程度&#xff0c;也可以用来…