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

C++ 享元模式与共享工厂模式详解

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术来高效地支持大量细粒度对象的复用。共享工厂模式通常与享元模式结合使用,用于管理和共享享元对象。

享元模式概念解析

核心思想

  1. 共享对象:将可以共享的状态(内部状态)与不可共享的状态(外部状态)分离

  2. 减少内存:通过共享相同内部状态的对象来减少内存使用

  3. 提高性能:减少对象创建的开销

主要组成部分

  1. 享元(Flyweight):包含可以被多个对象共享的内部状态

  2. 具体享元(Concrete Flyweight):实现享元接口并存储内部状态

  3. 非共享具体享元(Unshared Concrete Flyweight):不需要共享的实现

  4. 享元工厂(Flyweight Factory):创建并管理享元对象,确保合理共享

  5. 客户端(Client):维护外部状态并调用享元对象

共享工厂模式概念

共享工厂模式是享元模式的配套模式,负责:

  1. 集中管理:统一管理享元对象的创建和共享

  2. 缓存机制:维护已创建的享元对象池

  3. 按需提供:当请求享元对象时,优先返回已有对象

代码示例

下面是一个完整的享元模式与共享工厂模式示例,包含详细注释:

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>// ==================== 享元接口和实现 ====================// 棋子颜色(内部状态)
enum class ChessColor { BLACK, WHITE };// 棋子位置(外部状态)
struct Position {int x;int y;
};// 享元接口
class ChessPiece {
public:virtual void draw(const Position& position) = 0;virtual ~ChessPiece() = default;
};// 具体享元:棋子类型
class ConcreteChessPiece : public ChessPiece {
private:ChessColor color_;  // 内部状态(可共享)std::string name_;  // 内部状态(可共享)public:ConcreteChessPiece(ChessColor color, const std::string& name): color_(color), name_(name) {}void draw(const Position& position) override {std::cout << (color_ == ChessColor::BLACK ? "黑" : "白") << "色" << name_ << "放置在(" << position.x << "," << position.y << ")" << std::endl;}
};// ==================== 享元工厂 ====================class ChessPieceFactory {
private:std::unordered_map<std::string, std::shared_ptr<ChessPiece>> pieces_;// 生成唯一键std::string getKey(ChessColor color, const std::string& name) {return std::to_string(static_cast<int>(color)) + "_" + name;}public:ChessPieceFactory() {// 预初始化一些常用棋子getChessPiece(ChessColor::BLACK, "车");getChessPiece(ChessColor::BLACK, "马");getChessPiece(ChessColor::WHITE, "车");getChessPiece(ChessColor::WHITE, "马");}std::shared_ptr<ChessPiece> getChessPiece(ChessColor color, const std::string& name) {std::string key = getKey(color, name);// 检查是否已存在auto it = pieces_.find(key);if (it != pieces_.end()) {std::cout << "复用已有棋子: " << key << std::endl;return it->second;}// 创建新棋子并加入池中std::cout << "创建新棋子: " << key << std::endl;auto piece = std::make_shared<ConcreteChessPiece>(color, name);pieces_[key] = piece;return piece;}void listPieces() const {std::cout << "\n当前棋子池中有 " << pieces_.size() << " 种棋子:" << std::endl;for (const auto& pair : pieces_) {std::cout << "- " << pair.first << std::endl;}}
};// ==================== 棋盘类(使用享元)====================class ChessBoard {
private:ChessPieceFactory& factory_;std::vector<std::pair<std::shared_ptr<ChessPiece>, Position>> pieces_;public:ChessBoard(ChessPieceFactory& factory) : factory_(factory) {}void placePiece(ChessColor color, const std::string& name, int x, int y) {auto piece = factory_.getChessPiece(color, name);pieces_.emplace_back(piece, Position{x, y});}void draw() {std::cout << "\n当前棋盘状态:" << std::endl;for (const auto& entry : pieces_) {entry.first->draw(entry.second);}}
};// ==================== 客户端代码 ====================int main() {std::cout << "=== 享元模式与共享工厂演示 ===" << std::endl;// 创建享元工厂(共享)ChessPieceFactory factory;// 创建两个棋盘(共享同一个工厂)ChessBoard board1(factory);ChessBoard board2(factory);// 在第一个棋盘上放置棋子board1.placePiece(ChessColor::BLACK, "车", 0, 0);board1.placePiece(ChessColor::BLACK, "马", 0, 1);board1.placePiece(ChessColor::WHITE, "车", 7, 7);board1.placePiece(ChessColor::WHITE, "马", 7, 6);// 在第二个棋盘上放置棋子(会复用部分棋子对象)board2.placePiece(ChessColor::BLACK, "车", 0, 0);board2.placePiece(ChessColor::WHITE, "马", 7, 6);board2.placePiece(ChessColor::BLACK, "象", 0, 2); // 新棋子类型board2.placePiece(ChessColor::WHITE, "后", 7, 3);  // 新棋子类型// 显示工厂中的棋子情况factory.listPieces();// 显示两个棋盘状态board1.draw();board2.draw();return 0;
}

模式优势

  1. 内存效率:大幅减少相似对象的数量,节省内存

  2. 性能提升:减少对象创建和垃圾回收的开销

  3. 集中管理:共享工厂集中管理共享对象

  4. 灵活性:外部状态可以动态变化,不影响共享的内部状态

适用场景

  1. 当应用程序使用了大量相似对象,造成很大存储开销时

  2. 对象的大多数状态可以外部化时

  3. 需要缓存和共享对象时

  4. 典型应用:

    • 游戏中的粒子系统、棋子、角色等

    • 文字处理程序中的字符对象

    • 图形编辑器中的图形对象

http://www.xdnf.cn/news/4262.html

相关文章:

  • Java学习手册:分库分表策略
  • ESP32- 开发笔记- 软件开发 5 -I2C
  • VMware Fusion安装win11 arm;使用Mac远程连接到Win
  • IBM BAW(原BPM升级版)使用教程:基本概念
  • 设备管理系统的功能架构与核心价值
  • Jesse James Garrett 用户体验方法论
  • 全格式文档转 Markdown 工具,Docker 一键部署,支持 API 调用
  • C# 实现PLC数据自动化定时采集与存储(无需界面,自动化运行)
  • 算法 | 长颖燕麦优化算法AOO,算法原理,公式,深度解析+性能实测(Python代码)
  • linux -c程序开发
  • 双目标清单——AI与思维模型【96】
  • 高等数学第四章---不定积分(§4.3分部积分法4.4有理真分式函数的不定积分)
  • 应对联网汽车带来的网络安全挑战
  • FTPS和SFTP(文件传输安全协议)
  • 拨叉831003加工工艺及钻φ22花键底孔夹具设计
  • 量子跃迁:破解未来计算的“时空密码”​
  • 如何在vscode中set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`
  • Linux下的c/c++开发之操作mysql数据库
  • 【东枫科技】代理英伟达产品:DPU
  • Android View#post()源码分析
  • Android 中解决 annotations 库多版本冲突问题
  • 网络安全等级保护有关工作事项[2025]
  • BGP优化
  • 【计算机网络-应用层】HTTP服务器原理理解以及C++编写
  • 从设备交付到并网调试:CET中电技术分布式光伏全流程管控方案详解
  • QT异步线程通信
  • Linux 更改内存交换 swap 为 zram 压缩,减小磁盘写入
  • Android学习总结之Java和kotlin区别
  • Listremove数据时报错:Caused by: java.lang.UnsupportedOperationException
  • 深度解读 ARM 全新白皮书——《重塑硅基:AI 时代的新基石》