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

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

相关推荐
派阿喵搞电子4 小时前
在UI界面内修改了对象名,在#include “ui_mainwindow.h“没更新
c++·qt·ubuntu·ui
C++ 老炮儿的技术栈5 小时前
UDP 与 TCP 的区别是什么?
开发语言·c++·windows·算法·visual studio
mochensage6 小时前
CSP信奥赛C++常用系统函数汇总
c++·信奥
mochensage6 小时前
C++信息学竞赛中常用函数的一般用法
java·c++·算法
fpcc6 小时前
跟我学c++中级篇——多线程中的文件处理
c++
5:007 小时前
云备份项目
linux·开发语言·c++
乄夜8 小时前
嵌入式面试高频(5)!!!C++语言(嵌入式八股文,嵌入式面经)
c语言·c++·单片机·嵌入式硬件·物联网·面试·职场和发展
YYDS3148 小时前
C++动态规划-01背包
开发语言·c++·动态规划
wydaicls9 小时前
十一.C++ 类 -- 面向对象思想
开发语言·c++
姜君竹9 小时前
QT的工程文件.pro文件
开发语言·c++·qt·系统架构