我所理解的设计模式(C++实现)——享元模式(Flyweight Pattern)

C++策略模式实战:从电商折扣到算法替换的设计模式应用 在软件工程中,设计模式是解决常见问题的可复用方案,其中策略模式(Strategy Pattern)作为一种行为型模式,通过将算法或行为封装为独立对象,实现与使用它们的上下文解耦。其核心原理在于定义统一的策略接口,让具体策略类实现该接口,而上下文类通过组合方式持有策略引用,从而在运行时动态切换算法。这一模式的技术价值在于提升代码的可维护性和扩展性,遵循开闭原则,使得系统能够灵活应对业务变化。在应用场景上,策略模式广泛用于电商促销引擎、数据压缩、加密算法、渲染引擎等需要多种算法替换的领域。本文以电商折扣计算为例 阅读详情

概述

想想我们编辑文档用的wps,文档里文字很多都是重复的,我们不可能为每一个出现的汉字都创建独立的空间,这样代价太大,最好的办法就是共享其中相同的部分,使得需要创建的对象降到最小,这个就是享元模式的核心,即运用共享技术有效地支持大量细粒度的对象。

享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。内蕴状态是存储在享元对象内部并且不会随环境改变而改变。因此内蕴状态并可以共享。

外蕴状态是随环境改变而改变的、不可以共享的状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态与内蕴状态是相互独立的。

类图与样例


抽象享元类(Flyweight)

它是所有具体享元类的超类。为这些类规定出需要实现的公共接口,那些需要外蕴状态(Exte的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。

具体享元类(ConcreteFlyweight)

具体享元类实现了抽象享元类所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元类又称为单纯具体享元类,因为复合享元类是由单纯具体享元角色通过复合而成的。

不能共享的具体享元类(UnsharableFlyweight)

不能共享的享元类,又叫做复合享元类。一个复合享元对象是由多个单享元对象组成,这些组成的对象是可以共享的,但是复合享元类本身并不能共享。

享元工厂类(FlyweightFactoiy)

享元工厂类负责创建和管理享元对象。当一个客户端对象请求一个享元对象的时候,享元工厂需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。

客户类(Client)

客户类需要自行存储所有享元对象的外蕴状态。


// CplusplusFlyweight.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <map>
using namespace std;
class Character  
{
public:
	virtual ~Character(){};

	virtual void SetSize(int, int) = 0;
	virtual void Display() = 0;
protected:
	Character(){};
	char m_chSymbol;
	int m_nWeight;
	int m_nHeight;
};

class CharacterA : public Character
{
public:
	CharacterA();
	virtual ~CharacterA();

	void SetSize(int, int);
	void Display();
};

CharacterA::CharacterA()
{
	this->m_chSymbol = 'A';
	this->m_nWeight = 100;
	this->m_nHeight = 200;
}

CharacterA::~CharacterA()
{

}
void CharacterA::SetSize(int nWeight, int nHeight)
{
	this->m_nWeight = nWeight;
	this->m_nHeight = nHeight;
}
void CharacterA::Display()
{
	cout << "CharacterA:" << m_chSymbol << "(" << m_nWeight << "," << m_nHeight << ")" << endl;
}

class CharacterB : public Character
{
public:
	CharacterB();
	virtual ~CharacterB();

	void SetSize(int, int);
	void Display();
};

CharacterB::CharacterB()
{
	this->m_chSymbol = 'B';
	this->m_nWeight = 100;
	this->m_nHeight = 200;
}

CharacterB::~CharacterB()
{

}

void CharacterB::SetSize(int nWeight, int nHeight)
{
	this->m_nWeight = nWeight;
	this->m_nHeight = nHeight;
}

void CharacterB::Display()
{
	cout << "CharacterB:" << m_chSymbol << "(" << m_nWeight << "," << m_nHeight << ")" << endl;
}

class CharacterFactory  
{
public:
	CharacterFactory();
	virtual ~CharacterFactory();

	Character* GetCharacter(char);
private:
	std::map<char, Character*> m_mChar;
};

CharacterFactory::CharacterFactory()
{
	m_mChar.insert(make_pair<char, Character*>('A', new CharacterA));
	m_mChar.insert(make_pair<char, Character*>('B', new CharacterB));
}

CharacterFactory::~CharacterFactory()
{

}

Character* CharacterFactory::GetCharacter(char chIn)
{
	map<char, Character*>::iterator it = m_mChar.find(chIn);
	if(it != m_mChar.end())
	{
		return (Character*)it->second;
	}

	return NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
	CharacterFactory* pFactory = new CharacterFactory;

	//内蕴状态 存储在享元对象内部并且不会随环境改变而改变
	Character* ch1 = pFactory->GetCharacter('A');
	ch1->Display();

	//外蕴状态 客户端保存
	Character* ch2 = pFactory->GetCharacter('B');
	ch2->SetSize(500, 800);
	ch2->Display();
	return 0;
}

要点

1、面向对象很好的解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight设计模式主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。

2、Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理。

3、享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。另外它将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。

适用性

当以下所有的条件都满足时,可以考虑使用享元模式:

1、一个系统有大量的对象。 

2、这些对象耗费大量的内存。 

3、这些对象的状态中的大部分都可以外部化。 

4、这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。 

5、软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。

满足以上的这些条件的系统可以使用享元对象。最后,使用享元模式需要维护一个记录了系统已有的所有享元的表,而这需要耗费资源。因此,应当在有足够多的享元实例可供共享时才值得使用享元模式。

优缺点

享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:

1、享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。

2、享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。


LCL_data原创于youkuaiyun.com【http://blog.youkuaiyun.com/lcl_data/article/details/8974679】

.NET String底层契约与驻留机制实战解析 字符串是编程中最基础也最易被误解的数据类型,其核心在于不可变性、驻留机制和IL特化指令构成的运行时契约。理解String并非语法糖,而是CLR强制执行的内存治理协议,能从根本上解释GC飙升、内存冗余与性能瓶颈的根源。本文从C语言字符数组演进切入,剖析string如何通过ldstr指令自动驻留、new string()绕过共享、Intern()引入强引用等关键机制,并结合Object.ReferenceEquals验证、dotMemory快照分析与Span<char>零分配优化等工程手段,为高频重复字符串(如 阅读详情

相关推荐

C++设计模式之——享元模式详解和代码案例

享元模式(Flyweight Pattern)是一种用于性能优化的设计模式,它通过共享对象来有效支持大量的细粒度对象,以减少内存消耗。这种模式适用于那些对象中大部分状态可以外部化,而只有少量内部状态(不随环境改变而改变的状态)的对象。在C++中实现享元模式案例展示

qqrrjj2011的博客 2036

【C++设计模式】4.11-享元模式(Flyweight)

C++ 23种设计模式之享元模式(Flyweight)。

luonong9586的博客 1401

C++设计模式之享元模式(Flyweight)

主要为大家详细介绍了C++设计模式之享元模式Flyweight,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

C++设计模式(14)——享元模式

C++ 享元模式

伍粟的博客 1274

国科大——形式语言与自动机理论(0812课程)——作业

此次作业题考察,包括但不限于有限自动机、无限自动机、正则文法、正则表达式以及正则语言的性质,题考查下推自动机相关的知识,题考查图灵机相关的知识。此课程建议本科学习过课程的同学选修,成绩占比:考试100%。此课程虽然留有作业,但可做也可不做,且不考勤。

qq_54145399的博客 705

2026快手爬虫终极指南:JA4+指纹绕过+sign全逆向+AES响应解密(附可运行代码)

快手2026反爬破解实战指南 本文深入剖析快手2026年最新反爬体系,提供完整的破解方案: 四层防御体系:从传输层(JA4+指纹)、应用层(sign参数)、设备层到行为层,90%的爬虫在前两层即被拦截 JA4+指纹绕过:使用curl_cffi模拟Chrome 124的TLS指纹,完美匹配真实浏览器特征 sign参数逆向:通过动态调试提取加密逻辑,Python实现MD5签名算法,包含参数排序和盐值处理 响应解密:破解AES-GCM加密接口数据,完整还原响应内容 技术亮点: 使用curl-impersonate

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1799

C++ 享元模式

C++ 享元模式

索命的博客 500

SAP ABAP CO核心扩展-为企业定制ZCKM3N物料价格分析增强(CKM3 CKM3N CKM8N)

这篇文章,将为大家讲述物料价格分析扩展增强(ZCKM3N)的方法和原理,并基于CKM3N的视图之一“CV成本组件”,教大家如何一步步实现批量输出多工厂物料的物料价格分析报表。

SAP李斌,本人承诺所有原创文章均不使用任何AI生成技术,请大家放心阅读。 3982

C++设计模式结构型模式———享元模式

享元对象最重要的就是对“内部状态”和“外部状态”做出了明确的区分,这是享元对象能够被共享的关键所在。内部状态:存储在享元对象内部的,一直不会发生改变的状态,这种状态可以被共享。例如,对于BlackPiece类对象,它的内部状态就是黑棋子,它一直代表黑棋子,不会发生改变。而对于WhitePiece类对象,它的内部状态就是白棋子,它一直代表白棋子,不会发生改变。内部状态一般可以作为享元类的成员变量而存在。外部状态:随着着外部环境和各种动作因素的改变而发生改变的状态,这种状态不可以被共享。

无敌岩雀的博客 1569

国网DLT698.45协议——采集系统、数据交换(三)

物理层规定了通信单元或其他终端设备与多功能电表的通信接口,接口的物理与电气特性。常见的物理层传输方式有对于RS485、红外、载波通信等通信信道。将数据包装成可传输的帧格式。1、根据通信配置参数完成端口的初始化配置,通信状态初始化为准备接收状态,初始化相关计数器及缓冲区指针。2、链路层及控制子模块负责通信数据的收发控制,各类超时问题的处理。无通信数据接收时,定时初始化通信端口。3、完成协议帧的解析及应答。

一个bug是bug,多个bug能work 8050

YOLO26涨点改进 | 全网首发Conv独家改进篇 | CVPR 2025 | 引入GCConv卷积改进YOLO26,含GCC3k2二次创新,能够捕捉更加丰富和复杂的特征信息,助力高效涨点

本文提出了一种基于GCConv模块的YOLO26目标检测模型改进方案。GCConv模块通过多路径结构增强特征学习能力,在训练阶段采用垂直多卷积和水平多路径配置,推理时重参数化为单一3x3卷积,显著提升推理速度而不损失性能。实验表明,该模块在复杂场景和多尺度目标检测任务中表现优异,特别适合资源受限的实时应用场景。文章详细介绍了GCConv的网络结构、核心代码实现、YAML配置文件修改方法,并提供了两种改进方案(GCConv和GCC3k2)的具体配置指导。

Ai缝合怪、助力小伙伴高效发论文 316

元对象我所理解的设计模式(C++实现)——享元模式(Flyweight Pattern)

这段时间个人几篇文章介绍了改元对象的文章. 关联文章的地址      概述     想想我们编辑文档用的wps,文档里文字很多都是重复的,我们弗成能为每个涌现的汉字都创建独立的空间,这样代价太大,最好的方法就是同享其中雷同的部分,使得需要创建的对象降到最小,这个就是享元模式的核心,即运用同享技巧有效地支持大批细粒度的对象。     享元对象能做到同享的关键是辨别内蕴状态(Internal ...

weixin_34113237的博客 339

密码学系列3-Elgamal加密及其IND-CPA安全性证明

但这没有任何影响,敌手本身就只能知道公钥,他并没有能力知道挑战者是否知道对应的私钥。所以上述整个游戏就是一个模拟实验,敌手无法区分挑战者运行的是这个模拟实验,还是真正的按照第一节的算法构造的实验(挑战者知道私钥…为什么合起来的时候有1/2:因为T既可能是随机的也可能是g^{ab},这两种情况概率为1/2。能够攻破Elgamal加密方案,那么挑战者利用敌手的能力构建下面游戏,来求解困难性问题DDH。就是挑战者选的随机数,虽然挑战者自己也不知道。),否则挑战者输出0,作为DDH的回答。

qq_41359358的博客 1249

设计模式十二:flyweight(享元模式)——对象结构型模式

flyweight(享元模式)——对象结构型模式 1.意图运用共享技术有效地支持大量细粒度对象 2.动机flyweight作为一个共享对象,可以同时在多个场景中使用,并且在每个场景中flyweight都可以作为一个独立的对象。flyweight不能为他所运行的场景做出任何假设,这里的关键概念是内部状态和外部状态之间的区别。内部状态存储于flyweight中,包含了flyweight...

weixin_30472035的博客 156

Vue Print Designer——一款让打印模板的设计变简单的可视化打印设计器

Vue Print Designer——一款让打印模板的设计变简单的可视化打印设计器

bjzhang75的博客 682

动态规划之【树形DP】第3课:树形DP应用案例实践2

动态规划之【树形DP】第3课:树形DP应用案例实践2

王老师青少年编程 759

12,享元模式(Flyweight Pattern)是以共享的方式高效的支持大量的细粒度的对象。...

想想我们编辑文档用的wps,文档里文字很多都是重复的,我们不可能为每一个出现的汉字都创建独立的空间,这样代价太大,最好的办法就是共享其中相同的部分,使得需要创建的对象降到最小,这个就是享元模式的核心,即运用共享技术有效地支持大量细粒度的对象。 享元对象能做到共享的关键是区分内蕴状态(InternalState)和外蕴状态(ExternalState)。 内蕴状态:是存储在享元对象内部并且不...

weixin_30632899的博客 94

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

[结构型模式] 享元模式的理解

[img]https://api5.yunpan.360.cn/intf.php?method=Share.getPublicThumbByNid&qid=108635719&nid=13770720612900268&size=800_600&devtype=web&v=1.0.1&rtick=14676152633757&share_qid=108635719&sign=e9b7100c3f2...

Jacky_Dai的专栏 201

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

C++命令模式实战:从解耦到实现撤销重做的文本编辑器

在软件工程中,设计模式是解决常见设计问题的经典方案,其中命令模式(Command Pattern)是一种行为型模式,它将请求封装为独立的对象,从而实现对请求的参数化、队列化与日志化。其核心原理是将“调用者”与“接收者”解耦,通过一个抽象命令接口统一操作,使得请求的发起者无需知道具体执行细节。这一模式的技术价值在于,它将操作提升为一等公民对象,便于实现复杂的控制流,如任务调度、事务管理和历史记录。在应用场景上,命令模式广泛应用于GUI事件处理、异步任务队列以及需要支持撤销(Undo)和重做(Redo)功能的系

weixin_33709364的博客 481

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++适配器模式实战:接口转换、遗留代码集成与STL应用

在软件工程中,接口设计是系统架构的核心环节,它直接影响代码的可维护性和扩展性。当不同模块或第三方库因接口不兼容而无法直接协作时,结构型设计模式提供了一套系统化的解决方案。适配器模式作为其中最常用的模式之一,其核心原理是通过一个中间层(适配器)将不兼容的接口转换为客户端期望的接口,类似于电源转接头的功能。这一模式的技术价值在于,它允许在不修改已有代码的前提下实现代码复用,显著降低了系统集成的成本和风险。在实际应用场景中,适配器模式常用于集成遗留代码、统一第三方库接口,以及在C++ STL算法中适配自定义容器。

cuanku6549的博客 422

JAVA面试题(1~95)《上》

1、面向对象的特征有哪些方面?  答:面向对象的特征主要有以下几个方面:  - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。  - 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性...

ywl470812087的博客 4963

C++ 设计模式——享元模式

享元模式也称为蝇量模式旨在解决面向对象程序设计中的性能问题。享元的英文名“Flyweight”意为“轻量级”,源于拳击比赛中较轻的选手。该模式的核心目标是让对象变得“轻”,即减少内存占用。在需要某个对象时,尽量共享已经创建的同类对象,以避免频繁使用 `new` 创建同类或相似的对象。在对象数量非常庞大的情况下,这种共享可以显著节省内存占用并提升程序运行效率。

慢慢记录,慢慢更新。 2027

C++设计模式——享元模式

什么是享元模式? 在GOF的《设计模式:可复用面向对象软件的基础》一书中对享元模式是这样说的:运用共享技术有效地支持大量细粒度的对象。 就如上面说的棋子,如果每个棋子都new一个对象,就会存在大量细粒度的棋子对象,这对服务器的内存空间是一种考验,也是一种浪费。我们都知道,比如我在2013号房间和别人下五子棋,2014号房间也有人在下五子棋,并不会因为我在2013号房间,而别人在2014号房间,而导致我们的棋子是不一样的。这就是说,2013号房间和2014号房间的棋子都是一样的,所有的五子棋房间的棋子都是

嵌入式与人工智能 766
上一篇: 我所理解的设计模式(C++实现)——外观模式(Facade Pattern)
下一篇: 我所理解的设计模式(C++实现)——代理模式(Proxy Pattern)
十八道胡同
博客等级 码龄20年 848粉丝 109原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值