跳转到内容

C++ 享元模式

来自代码酷
Admin留言 | 贡献2025年4月28日 (一) 21:29的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)

模板:编程概念导航

概述[编辑 | 编辑源代码]

享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象减少内存使用,特别适用于存在大量相似对象的场景。其核心思想是将对象的内在状态(可共享部分)与外在状态(不可共享部分)分离,通过共享内在状态来优化资源消耗。

核心概念[编辑 | 编辑源代码]

  • 内在状态(Intrinsic State):对象的固定部分,可被多个上下文共享(例如字符的字体、颜色)。
  • 外在状态(Extrinsic State):对象的可变部分,由客户端代码传递(例如字符在文本中的位置)。

适用场景[编辑 | 编辑源代码]

  • 系统中存在大量相似对象,且内存占用过高。
  • 对象的大部分状态可以外部化。
  • 需要缓存或共享对象状态(如游戏中的粒子系统、文本编辑器中的字符渲染)。

结构[编辑 | 编辑源代码]

classDiagram class Flyweight { <<interface>> +operation(extrinsicState) } class ConcreteFlyweight { -intrinsicState +operation(extrinsicState) } class FlyweightFactory { -flyweights: Map +getFlyweight(key) } class Client { -flyweights: Flyweight[] } Flyweight <|-- ConcreteFlyweight FlyweightFactory o-- Flyweight Client --> FlyweightFactory Client --> Flyweight

代码示例[编辑 | 编辑源代码]

以下示例展示如何用享元模式优化文本编辑器中的字符渲染:

  
#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”)可被多个字符共享,仅存储一次而非每个字符单独保存。

优缺点[编辑 | 编辑源代码]

享元模式分析
优点 缺点
减少内存占用 增加代码复杂度
提高性能(减少对象创建) 需要妥善管理共享状态
适用于大规模对象复用 可能引入线程安全问题

数学建模[编辑 | 编辑源代码]

假设系统中有 N 个对象,享元模式将内存占用从 O(N) 降低至 O(K)K 为唯一内在状态的数量,通常 KN)。

扩展思考[编辑 | 编辑源代码]

  • 结合工厂模式管理享元对象的生命周期。
  • 使用弱引用(如C++的std::weak_ptr)避免内存泄漏。
  • 在多线程环境中,需对享元工厂加锁以保证线程安全。

模板:设计模式提示