C++ 享元模式与共享工厂模式详解
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术来高效地支持大量细粒度对象的复用。共享工厂模式通常与享元模式结合使用,用于管理和共享享元对象。
享元模式概念解析
核心思想
-
共享对象:将可以共享的状态(内部状态)与不可共享的状态(外部状态)分离
-
减少内存:通过共享相同内部状态的对象来减少内存使用
-
提高性能:减少对象创建的开销
主要组成部分
-
享元(Flyweight):包含可以被多个对象共享的内部状态
-
具体享元(Concrete Flyweight):实现享元接口并存储内部状态
-
非共享具体享元(Unshared Concrete Flyweight):不需要共享的实现
-
享元工厂(Flyweight Factory):创建并管理享元对象,确保合理共享
-
客户端(Client):维护外部状态并调用享元对象
共享工厂模式概念
共享工厂模式是享元模式的配套模式,负责:
-
集中管理:统一管理享元对象的创建和共享
-
缓存机制:维护已创建的享元对象池
-
按需提供:当请求享元对象时,优先返回已有对象
代码示例
下面是一个完整的享元模式与共享工厂模式示例,包含详细注释:
#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;
}
模式优势
-
内存效率:大幅减少相似对象的数量,节省内存
-
性能提升:减少对象创建和垃圾回收的开销
-
集中管理:共享工厂集中管理共享对象
-
灵活性:外部状态可以动态变化,不影响共享的内部状态
适用场景
-
当应用程序使用了大量相似对象,造成很大存储开销时
-
对象的大多数状态可以外部化时
-
需要缓存和共享对象时
-
典型应用:
-
游戏中的粒子系统、棋子、角色等
-
文字处理程序中的字符对象
-
图形编辑器中的图形对象
-