C++ 享元模式
外观
概述[编辑 | 编辑源代码]
享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象减少内存使用,特别适用于存在大量相似对象的场景。其核心思想是将对象的内在状态(可共享部分)与外在状态(不可共享部分)分离,通过共享内在状态来优化资源消耗。
核心概念[编辑 | 编辑源代码]
- 内在状态(Intrinsic State):对象的固定部分,可被多个上下文共享(例如字符的字体、颜色)。
- 外在状态(Extrinsic State):对象的可变部分,由客户端代码传递(例如字符在文本中的位置)。
适用场景[编辑 | 编辑源代码]
- 系统中存在大量相似对象,且内存占用过高。
- 对象的大部分状态可以外部化。
- 需要缓存或共享对象状态(如游戏中的粒子系统、文本编辑器中的字符渲染)。
结构[编辑 | 编辑源代码]
代码示例[编辑 | 编辑源代码]
以下示例展示如何用享元模式优化文本编辑器中的字符渲染:
#include <iostream>
#include <unordered_map>
#include <string>
// 享元接口
class Character {
public:
virtual void display(int position) = 0;
virtual ~Character() = default;
};
// 具体享元类
class ConcreteCharacter : public Character {
private:
char symbol_; // 内在状态(可共享)
public:
explicit ConcreteCharacter(char symbol) : symbol_(symbol) {}
void display(int position) override { // 外在状态由参数传递
std::cout << "Character '" << symbol_ << "' at position " << position << std::endl;
}
};
// 享元工厂
class CharacterFactory {
private:
std::unordered_map<char, Character*> characters_;
public:
Character* getCharacter(char key) {
if (characters_.find(key) == characters_.end()) {
characters_[key] = new ConcreteCharacter(key);
}
return characters_[key];
}
~CharacterFactory() {
for (auto& pair : characters_) {
delete pair.second;
}
}
};
// 客户端代码
int main() {
CharacterFactory factory;
// 模拟文本中的字符
std::string text = "Hello, Flyweight!";
for (int i = 0; i < text.size(); ++i) {
Character* character = factory.getCharacter(text[i]);
character->display(i); // 位置是外在状态
}
return 0;
}
输出示例[编辑 | 编辑源代码]
Character 'H' at position 0 Character 'e' at position 1 Character 'l' at position 2 Character 'l' at position 3 Character 'o' at position 4 ...
代码解析[编辑 | 编辑源代码]
1. ConcreteCharacter 存储内在状态(如字符符号),而外在状态(如位置)通过参数传递。 2. CharacterFactory 确保相同字符仅创建一个实例。 3. 客户端通过工厂获取享元对象,避免重复创建。
实际应用案例[编辑 | 编辑源代码]
游戏开发中的粒子系统[编辑 | 编辑源代码]
在游戏中,大量粒子(如子弹、火焰)可能共享相同的纹理和动画,但位置和速度不同。享元模式可将纹理作为内在状态共享,而位置作为外在状态动态传递。
文档编辑器中的格式设置[编辑 | 编辑源代码]
文本中的相同字体(如“Arial 12pt”)可被多个字符共享,仅存储一次而非每个字符单独保存。
优缺点[编辑 | 编辑源代码]
优点 | 缺点 |
---|---|
减少内存占用 | 增加代码复杂度 |
提高性能(减少对象创建) | 需要妥善管理共享状态 |
适用于大规模对象复用 | 可能引入线程安全问题 |
数学建模[编辑 | 编辑源代码]
假设系统中有 个对象,享元模式将内存占用从 降低至 ( 为唯一内在状态的数量,通常 )。
扩展思考[编辑 | 编辑源代码]
- 结合工厂模式管理享元对象的生命周期。
- 使用弱引用(如C++的
std::weak_ptr
)避免内存泄漏。 - 在多线程环境中,需对享元工厂加锁以保证线程安全。