目錄
一、問題背景
二、模式選擇
三、代碼實現
四、總結討論
一、問題背景
????????享元模式(Flyweight Pattern)在對象存儲優化中的應用
????????在面向對象系統的設計與實現中,創建對象是最常見的操作之一。然而,如果一個應用程序使用了過多的對象,尤其是大量輕量級(細粒度)的對象,可能會導致巨大的存儲開銷。例如,在文檔編輯器的設計中,如果為每個字母創建一個獨立的對象,系統中可能會出現大量重復的對象,從而造成存儲浪費。例如,字母“a”在文檔中可能出現 100,000 次,實際上這 100,000 個“a”可以共享同一個對象。
????????然而,由于不同位置的字母“a”可能有不同的顯示效果(如字體、大小等),我們可以將對象的狀態分為“內部狀態”和“外部狀態”。內部狀態是對象共享的、不變的部分,而外部狀態則可以在需要時作為參數傳遞給對象(例如在顯示時傳遞字體、大小等信息)。
二、模式選擇
????????上述問題可以通過**享元模式(Flyweight Pattern)**來解決。享元模式的核心思想是通過共享大量細粒度對象來減少存儲開銷。其典型結構如下:
????????FlyweightFactory:類似于工廠模式的對象構造工廠,用于管理對象的創建和共享。
????????Flyweight:享元對象的基類,定義了內部狀態和外部狀態的處理方式。
????????ConcreteFlyweight:具體的享元對象實現,包含內部狀態。
三、代碼實現
????????以下是享元模式的完整實現代碼,采用 C++ 編寫。
代碼片段 1:Flyweight.h
#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
#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
#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
#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
#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 種設計模式解析