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

文章目录

      • 享元模式(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;

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单机游戏《野狗子》游戏运行时提示dbghelp.dll缺失是什么原因?dbghelp.dll缺失要怎么解决?

《野狗子》游戏运行时提示dbghelp.dll缺失&#xff1a;原因与解决方案 在畅游《野狗子》这款引人入胜的游戏世界时&#xff0c;突然遭遇“dbghelp.dll缺失”的错误提示&#xff0c;无疑会给玩家的探险之旅蒙上一层阴影。作为一名深耕软件开发领域的从业者&#xff0c;我深知此…

CASA模型相关遥感数据及MODIS NDVI、FPAR遥感产品数据时序重建

植被作为陆地生态系统的重要组成部分对于生态环境功能的维持具有关键作用。植被净初级生产力&#xff08;Net Primary Productivity, NPP&#xff09;是指单位面积上绿色植被在单位时间内由光合作用生产的有机质总量扣除自养呼吸的剩余部分。植被NPP是表征陆地生态系统功能及可…

如何在谷歌浏览器中设置桌面快捷方式

在日常使用电脑时&#xff0c;反复在浏览器中输入经常访问的网址不仅耗时&#xff0c;而且降低了工作效率。为了解决这一问题&#xff0c;我们可以通过在主屏幕上创建谷歌浏览器的快捷方式来简化操作。本文将详细介绍如何在Windows和Mac系统中实现这一功能。 一、步骤概述 1. …

SYD881X RTC定时器事件在调用timeAppClockSet后会出现比较大的延迟

RTC定时器事件在调用timeAppClockSet后会出现比较大的延迟 这里RTC做了两个定时器一个是12秒,一个是185秒: #define RTCEVT_NUM ((uint8_t) 0x02)//当前定时器事件数#define RTCEVT_12S ((uint32_t) 0x0000002)//定时器1s事件 /*整分钟定时器事件&#xff0c;因为其余的…

UE5喷涂功能

许多FPS/TPS 游戏都有喷涂、涂鸦功能 其实原理很简单&#xff0c;就是利用了延迟贴花实现的 我们从网上随便找一张图 创建一个材质&#xff0c;材质域选择延迟贴花 混合模式选择半透明&#xff0c;自发光强度可以看感觉调整 材质做好之后编译保存&#xff0c;新建一个Actor…

攻防世界 ics-06

开启场景 可以交互的按钮不是很多&#xff0c;没有什么有用信息&#xff0c;查看页面源代码找到了index.php &#xff0c;后面跟着“报表中心” 传参访问 /index.php 看到了参数 id1&#xff0c;用 burp 抓包爆破&#xff08;这里应该不是 sql 注入&#xff09; 2333 的长度与众…

Flutter 异步编程简述

1、isolate 机制 1.1 基本使用 Dart 是基于单线程模型的语言。但是在开发当中我们经常会进行耗时操作比如网络请求&#xff0c;这种耗时操作会堵塞我们的代码。因此 Dart 也有并发机制 —— isolate。APP 的启动入口main函数就是一个类似 Android 主线程的一个主 isolate。与…

RT-DETR融合[CVPR2023]FFTformer中的FSAS模块

RT-DETR使用教程&#xff1a; RT-DETR使用教程 RT-DETR改进汇总贴&#xff1a;RT-DETR更新汇总贴 《Efficient Frequency Domain-based Transformers for High-Quality Image Deblurring》 一、 模块介绍 论文链接&#xff1a;https://arxiv.org/abs/2211.12250 代码链接&…

新手SEO指南如何快速入门与提升网站排名

内容概要 搜索引擎优化&#xff08;SEO&#xff09;是提高网站可见度和排名的重要手段&#xff0c;尤其对新手来说&#xff0c;掌握其基本概念和实用技巧至关重要。本文将针对新手提供一系列的指导&#xff0c;帮助你快速入门并逐步提升网站排名。 首先&#xff0c;了解SEO的…

【终端工具】FinalShell v4.5.12 官方版

1.下载地址 【终端工具】FinalShell v4.5.12 官方版 2.简介 FinalShell是一款免费的跨平台远程管理工具&#xff0c;专为开发者和运维人员设计。它支持通过 SSH、SFTP 等方式连接到 Linux 和 Windows 服务器&#xff0c;提供类似于终端的操作界面。除了常规的远程登录功能&a…

003-aop-切点表达式

spring-aop-切点表达式 表达式复用 spring-aop-pom依赖

VBA技术资料MF243:利用第三方软件复制PDF数据到EXCEL

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

03--KVM虚拟化

前言&#xff1a;这里开始涉及到云计算内容&#xff0c;虚拟化使云计算发展&#xff0c;云计算推动虚拟化进步&#xff0c;两者相辅相成&#xff0c;这一章总结一下kvm虚拟化的解决方案。 1、基础概念 1.1、云计算 以前要完成信息处理, 是需要在一个客观存在的计算机上完成的…

EasyGBS国标GB28181平台P2P远程访问故障排查指南:客户端角度的排查思路

在现代视频监控系统中&#xff0c;P2P&#xff08;点对点&#xff09;技术因其便捷性和高效性而被广泛应用。然而&#xff0c;当用户在使用P2P远程访问时遇到设备不在线或无法访问的问题时&#xff0c;有效的排查方法显得尤为重要。本文将从客户端的角度出发&#xff0c;详细探…

开放词汇目标检测(Open-Vocabulary Object Detection, OVOD)综述

定义 开放词汇目标检测&#xff08;Open-Vocabulary Object Detection, OVOD&#xff09;是一种目标检测任务&#xff0c;旨在检测和识别那些未在训练集中明确标注的物体类别。传统的目标检测模型通常只能识别有限数量的预定义类别&#xff0c;而OVOD模型则具有识别“开放词汇…

《信管通低代码信息管理系统开发平台》Windows环境安装说明

1 简介 《信管通低代码信息管理系统应用平台》提供多环境软件产品开发服务&#xff0c;包括单机、局域网和互联网。我们专注于适用国产硬件和操作系统应用软件开发应用。为事业单位和企业提供行业软件定制开发&#xff0c;满足其独特需求。无论是简单的应用还是复杂的系统&…

畅捷通-条件竞争

反编译dll 逻辑上很清晰了。取得上传数据然后直接写入Templates目录里去&#xff0c;且写入路径直接拼接文件名&#xff0c;说明写入路径可控。然后马上又调用Delete方法删除文件。看起来貌似很正常的样子&#xff0c;但实际上这里已经出现了严重的安全问题。首先是未限制上传…

重温设计模式--工厂模式(简单、工厂、抽象)

文章目录 工厂模式定义工厂模式通常可以细分为以下几种类型1、简单工厂模式&#xff08;Simple Factory Pattern&#xff09;2、工厂方法模式&#xff08;Factory Method Pattern&#xff09;3、抽象工厂模式&#xff08;Abstract Factory Pattern) UML 图1、简单工厂模式UML2、…

华为手机鸿蒙4.2连接不上adb

1、下载HiSuite华为手机助手 https://consumer.huawei.com/cn/support/hisuite/ 2、安装后点连接 3、就可以adb连接了

重温设计模式--代理模式

文章目录 定义UML图代理模式主要有以下几种常见类型&#xff1a;代理模式涉及的主要角色有&#xff1a;C 代码示例 定义 代理模式&#xff08;Proxy Pattern&#xff09;属于结构型设计模式&#xff0c;它为其他对象提供一种代理以控制对这个对象的访问。 通过引入代理对象&am…