【第十节】C++设计模式(结构型模式)-Flyweight( 享元)模式

目录

一、问题背景

二、模式选择

三、代码实现

四、总结讨论


一、问题背景

享元模式(Flyweight Pattern)在对象存储优化中的应用

在面向对象系统的设计与实现中,创建对象是最常见的操作之一。然而,如果一个应用程序使用了过多的对象,尤其是大量轻量级(细粒度)的对象,可能会导致巨大的存储开销。例如,在文档编辑器的设计中,如果为每个字母创建一个独立的对象,系统中可能会出现大量重复的对象,从而造成存储浪费。例如,字母"a"在文档中可能出现 100,000 次,实际上这 100,000 个"a"可以共享同一个对象。

然而,由于不同位置的字母"a"可能有不同的显示效果(如字体、大小等),我们可以将对象的状态分为"内部状态"和"外部状态"。内部状态是对象共享的、不变的部分,而外部状态则可以在需要时作为参数传递给对象(例如在显示时传递字体、大小等信息)。

二、模式选择

上述问题可以通过**享元模式(Flyweight Pattern)**来解决。享元模式的核心思想是通过共享大量细粒度对象来减少存储开销。其典型结构如下:

FlyweightFactory:类似于工厂模式的对象构造工厂,用于管理对象的创建和共享。

Flyweight:享元对象的基类,定义了内部状态和外部状态的处理方式。

ConcreteFlyweight:具体的享元对象实现,包含内部状态。

三、代码实现

以下是享元模式的完整实现代码,采用 C++ 编写。

代码片段 1:Flyweight.h

cpp 复制代码
#ifndef _FLYWEIGHT_H_
#define _FLYWEIGHT_H_

#include <string>
using namespace std;

class Flyweight {
public:
    virtual ~Flyweight();
    virtual void Operation(const string& extrinsicState); // 外部状态的处理
    string GetIntrinsicState(); // 获取内部状态
protected:
    Flyweight(string intrinsicState); // 构造函数,初始化内部状态
private:
    string _intrinsicState; // 内部状态
};

class ConcreteFlyweight : public Flyweight {
public:
    ConcreteFlyweight(string intrinsicState); // 构造函数
    ~ConcreteFlyweight();
    void Operation(const string& extrinsicState); // 外部状态的处理
};

#endif //~_FLYWEIGHT_H_

代码片段 2:Flyweight.cpp

cpp 复制代码
#include "Flyweight.h"
#include <iostream>
using namespace std;

Flyweight::Flyweight(string intrinsicState) {
    this->_intrinsicState = intrinsicState;
}

Flyweight::~Flyweight() {}

void Flyweight::Operation(const string& extrinsicState) {
    // 默认实现为空
}

string Flyweight::GetIntrinsicState() {
    return this->_intrinsicState;
}

ConcreteFlyweight::ConcreteFlyweight(string intrinsicState) : Flyweight(intrinsicState) {
    cout << "ConcreteFlyweight Build....." << intrinsicState << endl;
}

ConcreteFlyweight::~ConcreteFlyweight() {}

void ConcreteFlyweight::Operation(const string& extrinsicState) {
    cout << "ConcreteFlyweight: 内蕴 [" << this->GetIntrinsicState() << "] 外蕴 [" << extrinsicState << "]" << endl;
}

代码片段 3:FlyweightFactory.h

cpp 复制代码
#ifndef _FLYWEIGHTFACTORY_H_
#define _FLYWEIGHTFACTORY_H_

#include "Flyweight.h"
#include <string>
#include <vector>
using namespace std;

class FlyweightFactory {
public:
    FlyweightFactory();
    ~FlyweightFactory();
    Flyweight* GetFlyweight(const string& key); // 获取享元对象
protected:
private:
    vector<Flyweight*> _fly; // 对象池
};

#endif //~_FLYWEIGHTFACTORY_H_

代码片段 4:FlyweightFactory.cpp

cpp 复制代码
#include "FlyweightFactory.h"
#include <iostream>
#include <cassert>
using namespace std;

FlyweightFactory::FlyweightFactory() {}

FlyweightFactory::~FlyweightFactory() {}

Flyweight* FlyweightFactory::GetFlyweight(const string& key) {
    vector<Flyweight*>::iterator it = _fly.begin();
    for (; it != _fly.end(); it++) {
        // 如果对象已存在,则直接返回
        if ((*it)->GetIntrinsicState() == key) {
            cout << "already created by users...." << endl;
            return *it;
        }
    }
    // 否则创建新对象并加入对象池
    Flyweight* fn = new ConcreteFlyweight(key);
    _fly.push_back(fn);
    return fn;
}

代码片段 5:main.cpp

cpp 复制代码
#include "Flyweight.h"
#include "FlyweightFactory.h"
#include <iostream>
using namespace std;

int main(int argc, char* argv[]) {
    FlyweightFactory* fc = new FlyweightFactory();
    Flyweight* fw1 = fc->GetFlyweight("hello"); // 获取享元对象
    Flyweight* fw2 = fc->GetFlyweight("world!"); // 获取享元对象
    Flyweight* fw3 = fc->GetFlyweight("hello"); // 获取享元对象
    return 0;
}

代码说明

享元模式在实现过程中,主要是为共享对象提供一个存放的"仓库"(对象池)。这里通过 C++ STL 中的 `vector` 容器来实现对象池的管理。需要注意的是,对象池的管理策略(查找、插入等)对性能有很大影响。这里使用了简单的顺序遍历来查找对象,但实际应用中可以使用更高效的索引策略,例如哈希表。

四、总结讨论

享元模式通过共享细粒度对象,有效地减少了系统中的对象数量,从而降低了存储开销。它特别适用于需要创建大量相似对象的场景,如文档编辑器、游戏中的粒子系统等。通过合理使用享元模式,可以显著提高系统的性能和资源利用率。

在以后讲到的**状态模式(State Pattern)和策略模式(Strategy Pattern)**中,可能会产生大量的对象,因此可以通过享元模式来优化存储开销。享元模式的核心思想是共享对象,从而减少系统中对象的数量,降低存储和计算资源的消耗。

参考学习:设计模式精解-GoF 23 种设计模式解析

相关推荐
HAH-HAH8 小时前
【蓝桥杯 2024 国 Java A】粉刷匠小蓝
c++·学习·数学·算法·职场和发展·蓝桥杯·组合数学
小吴同学·9 小时前
OPC Client第10讲:实现主界面;获取初始界面传来的所有配置信息config【C++读写Excel:xlnx;ODBC;缓冲区】
c++·wxwidgets
边疆.9 小时前
【C++】继承详解
开发语言·c++·继承
hweiyu009 小时前
C++设计模式,高级开发,算法原理实战,系统设计与实战(视频教程)
c++·算法·设计模式
我真的是大笨蛋9 小时前
从源码和设计模式深挖AQS(AbstractQueuedSynchronizer)
java·jvm·设计模式
十年编程老舅9 小时前
‌C++左值与右值:从基础概念到核心应用‌
linux·c++·右值引用·c++17·c++左值·c++右值·左值引用
John_ToDebug10 小时前
Chrome性能黑魔法:深入浅出PGO优化与实战指南
c++·chrome
和光同尘 、Y_____10 小时前
BRepMesh_IncrementalMesh 重构生效问题
c++·算法·图形渲染
起个名字费劲死了11 小时前
手眼标定之已知同名点对,求解转换RT,备份记录
c++·数码相机·机器人·几何学·手眼标定
雅雅姐11 小时前
C++中的单例模式的实现
c++