1. 程式人生 > >設計模式---對象性能模式之享元模式(Flyweight)

設計模式---對象性能模式之享元模式(Flyweight)

ret 大量 根據 利用 問題 字母 只讀 時代 帶來

一:概念

通過與其他類似對象共享數據來減少內存占用
如果一個應用程序使用了太多的對象, 就會造成很大的存儲開銷。 
特別是對於大量輕量級 (細粒度)的對象,比如在文檔編輯器的設計過程中,我們如果為每個字母創建一個對象的話,系統可能會因為大量的對象而造成存儲開銷的浪費。
例如一個字母“a”在文檔中出現了100000 次,而實際上我們可以讓這一萬個字母“a”共享一個對象,當然因為在不同的位置可能字母“a”有不同的顯示效果(例如字體和大小等設置不同) ,
在這種情況我們可以為將對象的狀態分為“外部狀態”和“內部狀態” ,
將可以被共享(不會變化)的狀態作為內部狀態存儲在對象中,而外部對象(例如上面提到的字體、大小等)我們可以在適當的時候將外部對象最為參數傳遞給對象(例如在顯示的時候,將字體、大小等信息傳遞給對象) 。 Flyweight 模式可以解決上面的問題,

二:動機

在軟件系統中采用純粹對象方案的問題 在於大量細粒度的對象會很快充斥在系統中,從而帶來很高的運行時代價——主要指內存需求方面的代價。
如何在避免大量·細粒度對象問題的同事,讓外部客戶程序仍然能夠透明地使用面向對象的方式來進行操作?

三:模式定義

運用共享技術有效地支持大量的細粒度對象                                        

                                               ——《設計模式》GoF

四:代碼講解

class Font {  //用來描述字體
private:

    //unique object key
    string key;
    
    //object state
    //....
    
public:
    Font(const string& key){  //利用這個key來創建對象
        //...
    }
};
class FontFactory{
private:
    map<string,Font* > fontPool;  //map映射key--對象指針
    
public: Font* GetFont(const string& key){ map<string,Font*>::iterator item=fontPool.find(key); if(item!=footPool.end()){ return fontPool[key];  //若存在則共享 } else{ Font* font = new Font(key);  //不存在則添加 fontPool[key]= font; return font; } } void clear(){ //... } };
實現是多種的,但是總體思想是一樣的

五:類圖(結構)

技術分享圖片

六:要點總結

(一)面向對象很好的解決了抽相性的問題,但是作為一個運行在機器中的程序實體,我們需要考慮對象的代價問題。Flyweight主要解決面向的代價問題,一般不觸及面向對象的抽象性問題。

(二)Flyweight采用對象共享的做法來降低系統中的對象的個數,從而降低細粒度對象給系統帶來的內存壓力。在具體實現方面,要註意對像狀態的處理。

註意:上面的Font對象一旦創建出來,狀態就無法更改了,是只讀的。共享最好就是只讀的,不允許隨便修改

(三)對象的數量太大,從而導致對像內存開銷加大——什麽樣的數量才算大?這需要我們仔細根據具體應用情況進行評估,而不能憑空臆斷。

字段,字節對齊,虛函數表指針(有10個虛函數,也只有一個虛函數表指針),總共加起來假設有10字段40字節
1024個對象:40*1024=40kb
102400個對象:40:1024*100=4000kb~4M
不能臆想,需要去評估,用於處理對象過多時使用享元模式

設計模式---對象性能模式之享元模式(Flyweight)