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

享元模式(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::map 或 std::unordered_map 缓存已创建的实例,键通常由内部状态组合构成:
立即学习“C++免费学习笔记(深入)”;
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++ 中落地:用工厂控制创建、用接口解耦使用、靠内部/外部状态分离实现高效复用。不复杂但容易忽略细节。











