0

0

c++如何实现享元模式 c++设计模式之Flyweight【实例】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2025-12-27 14:02:02

|

441人浏览过

|

来源于php中文网

原创

享元模式通过共享内部状态、分离外部状态来减少内存占用。C++中以字符渲染为例,定义享元接口和具体类,工厂用map缓存实例,客户端通过工厂获取并传入外部状态调用display。

c++如何实现享元模式 c++设计模式之flyweight【实例】

享元模式(Flyweight)在 C++ 中主要用于减少内存占用,通过共享大量细粒度对象来避免创建过多重复实例。它的核心是将对象状态分为 内部状态(可共享、不可变)和 外部状态(不可共享、由客户端维护)。下面用一个典型场景——文字编辑器中字符渲染——来演示如何用 C++ 实现享元模式。

享元接口与具体享元类

定义统一接口,让所有享元对象对外提供一致的使用方式。内部状态(如字体、字号、颜色)在构造时固定,不随上下文变化:

class CharacterFlyweight {
public:
    virtual ~CharacterFlyweight() = default;
    virtual void display(char c, int x, int y) const = 0; // 外部状态:位置、具体字符
};

class ConcreteCharacter : public CharacterFlyweight { private: const char m_font; const int m_size; const std::string m_color;

public: ConcreteCharacter(char font, int size, const std::string& color) : m_font(font), m_size(size), m_color(color) {}

void display(char c, int x, int y) const override {
    std::cout << "Char '" << c 
              << "' at (" << x << "," << y << ") "
              << "with font " << m_font 
              << ", size " << m_size 
              << ", color " << m_color << "\n";
}

};

享元工厂:管理共享对象池

工厂负责按需创建或复用享元对象。用 std::mapstd::unordered_map 缓存已创建的实例,键通常由内部状态组合构成:

立即学习C++免费学习笔记(深入)”;

Looka
Looka

AI辅助Logo和品牌设计工具

下载
class CharacterFactory {
private:
    std::map, std::unique_ptr> m_pool;

public: CharacterFlyweight* getCharacter(char font, int size, const std::string& color) { auto key = std::make_tuple(font, size, color); if (m_pool.find(key) == m_pool.end()) { m_pool[key] = std::make_unique(font, size, color); } return m_pool[key].get(); } };

客户端代码:使用享元而非直接 new

客户端不再自行构造享元,而是向工厂请求;每次调用 display() 传入外部状态(坐标、实际字符),实现“一份享元,多次显示”:

int main() {
    CharacterFactory factory;
// 获取两个相同样式的享元(实际只创建一次)
CharacterFlyweight* bold12red = factory.getCharacter('B', 12, "red");
CharacterFlyweight* bold12red2 = factory.getCharacter('B', 12, "red"); // 复用

// 不同样式会创建新实例
CharacterFlyweight* italic10blue = factory.getCharacter('I', 10, "blue");

// 渲染不同位置的相同样式字符
bold12red->display('H', 0, 0);
bold12red2->display('e', 1, 0);
italic10blue->display('l', 2, 0);

return 0;

}

关键注意事项

  • 内部状态必须是 不可变的(建议用 const 成员),否则共享会导致逻辑错误
  • 享元对象应是 无状态的或仅依赖传入的外部参数,不能持有上下文相关数据
  • 工厂类可加线程安全封装(如加锁),适用于多线程环境
  • 若享元数量极少或生命周期极短,引入享元反而增加复杂度,需权衡

这个例子展示了享元模式如何在 C++ 中落地:用工厂控制创建、用接口解耦使用、靠内部/外部状态分离实现高效复用。不复杂但容易忽略细节。

相关专题

更多
c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

517

2023.09.20

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

984

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

41

2025.10.17

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

465

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

2

2025.12.24

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

73

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

24

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

36

2025.11.17

ip地址修改教程大全
ip地址修改教程大全

本专题整合了ip地址修改教程大全,阅读下面的文章自行寻找合适的解决教程。

27

2025.12.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号