C++设计模式之享元模式

动机

在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价------主要指内存需求方面的代价。

如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地适用面向对象的方式来进行操作?

代码举例:创建字体对象时,同一个key的字体对象只有一个,而不是有很多

cpp 复制代码
// Font.h
#pragma once

#include <string>

class Font {
private:
    // 字体对象的唯一标识符
    std::string key;

    // 字体对象的状态(可能包含其他属性,这里未具体展示)
    // ....

public:
    // 构造函数,根据传入的 key 初始化字体对象
    Font(const std::string& key) : key(key) {
        // ...
    }
};

// FontFactory.h
#pragma once

#include <map>
#include "Font.h"

class FontFactory {
private:
    // 存储已创建的字体对象,key 是字体对象的唯一标识符,value 是对应的字体对象指针
    std::map<std::string, Font*> fontPool;

public:
    // 获取字体对象
    Font* GetFont(const std::string& key);

    // 清理字体池
    void clear();
};

// FontFactory.cpp
#include "FontFactory.h"

Font* FontFactory::GetFont(const std::string& key) {
    // 查找字体池中是否已存在对应 key 的字体对象
    auto iter = fontPool.find(key);

    if (iter != fontPool.end()) {
        // 如果存在,则直接返回已有的字体对象
        return iter->second;
    } else {
        // 如果不存在,则创建新的字体对象,并加入字体池
        Font* font = new Font(key);
        fontPool[key] = font;
        return font;
    }
}

void FontFactory::clear() {
    // 清理字体池中的所有字体对象
    for (auto& entry : fontPool) {
        delete entry.second;
    }
    fontPool.clear();
}

享元模式定义

运用共享技术有效地支持大量细粒度的对象。

chatGPT给出的享元模式的例子

以下是一个简单的 C++ 代码例子,演示了享元模式的实现。这个例子以文本编辑器中的字符格式化为场景。

cpp 复制代码
#include <iostream>
#include <map>

// 享元接口
class CharacterFormat {
public:
    virtual void applyFormat() const = 0;
};

// 具体享元类,代表不同的字符格式
class BoldFormat : public CharacterFormat {
public:
    void applyFormat() const override {
        std::cout << "Applying Bold Format\n";
    }
};

class ItalicFormat : public CharacterFormat {
public:
    void applyFormat() const override {
        std::cout << "Applying Italic Format\n";
    }
};

class UnderlineFormat : public CharacterFormat {
public:
    void applyFormat() const override {
        std::cout << "Applying Underline Format\n";
    }
};

// 享元工厂类,负责创建和管理享元对象
class CharacterFormatFactory {
private:
    std::map<std::string, CharacterFormat*> formatPool;

public:
    CharacterFormat* getFormat(const std::string& key) {
        auto iter = formatPool.find(key);

        if (iter != formatPool.end()) {
            return iter->second;
        } else {
            CharacterFormat* format = nullptr;

            if (key == "Bold") {
                format = new BoldFormat();
            } else if (key == "Italic") {
                format = new ItalicFormat();
            } else if (key == "Underline") {
                format = new UnderlineFormat();
            }

            formatPool[key] = format;
            return format;
        }
    }
};

// 客户端代码
int main() {
    CharacterFormatFactory formatFactory;

    // 用户输入的字符格式
    std::string userInput = "Bold";

    // 通过享元工厂获取或创建字符格式对象
    CharacterFormat* format = formatFactory.getFormat(userInput);

    // 应用字符格式
    if (format) {
        format->applyFormat();
    } else {
        std::cout << "Invalid Format\n";
    }

    // 释放资源
    delete format;

    return 0;
}

在这个例子中,CharacterFormat 是享元接口,而 BoldFormat、ItalicFormat、UnderlineFormat 是具体的享元类。CharacterFormatFactory 是享元工厂类,负责创建和管理享元对象。在客户端代码中,用户输入字符格式的信息,通过享元工厂获取或创建相应的字符格式对象,并应用该格式。这样,相同的字符格式对象可以被多次共享,减少了资源的重复创建。

要点总结

面向对象很好地解决了抽象性的问题,但是作为一个运行在机器 中的程序实体,我们需要考虑对象的代价问题。Flyweight主要解 决面向对象的代价问题,一般不触及面向对象的抽象性问题。

Flyweight采用对象共享的做法来降低系统中对象的个数,从而降 低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对 象状态的处理。

对象的数量太大从而导致对象内存开销加大------什么样的数量才 算大?这需要我们仔细的根据具体应用情况进行评估,而不能凭空 臆断。

相关推荐
ziguo112215 小时前
深入浅出 C/C++ 数据类型:从入门到踩坑
linux·c语言·c++·windows·visual studio
白色冰激凌15 小时前
[SECS/GEM研究] (三)SECS-I 串口上消息怎么分块和重传
c++·secs/gem
光头闪亮亮15 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(中)
android·c++·go
光头闪亮亮15 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(下)
android·c++·go
_wyt00116 小时前
洛谷 P7912 [CSP-J 2021] 小熊的果篮 题解
c++·队列
choumin17 小时前
创建型模式——原型模式
c++·设计模式·原型模式·创建型模式
code_pgf17 小时前
C/C++ 常用容器功能汇总
c语言·开发语言·c++
37.2℃99517 小时前
Claude Design哪个公司技术好
python·设计模式
阿懂在掘金18 小时前
Vue 弹窗新范式——代码减少、复用翻倍与 AI 时代的前端基建
前端·设计模式·前端框架
王维同学19 小时前
Credential Provider、Filter 与 PLAP 的 CLSID 枚举
c++·windows·安全·注册表