設計模式 11 享元模式 Flyweight

2021-09-08 10:53:42 字數 2950 閱讀 7575

轉 

問題 在物件導向系統的設計何實現中,建立物件是最為常見的操作。這裡面就有乙個問題:

如果乙個應用程式使用了太多的物件,就會造成很大的儲存開銷。特別是對於大量輕量級(細

粒度)的物件,比如在文件編輯器的設計過程中,我們如果為沒有字母建立乙個物件的話,

系統可能會因為大量的物件而造成儲存開銷的浪費。例如乙個字母「a」在文件**現了

100000 次,而實際上我們可以讓這一萬個字母「a」共享乙個物件,當然因為在不同的位置

可能字母「a」有不同的顯示效果(例如字型和大小等設定不同),在這種情況我們可以為將

物件的狀態分為「外部狀態」和「內部狀態」,將可以被共享(不會變化)的狀態作為內部

狀態儲存在物件中,而外部物件(例如上面提到的字型、大小等)我們可以在適當的時候將

外部物件最為引數傳遞給物件(例如在顯示的時候,將字型、大小等資訊傳遞給物件)。

可以從圖 2-1 中看出,flyweight 模式中有乙個類似 factory 模式的物件構造工廠

flyweightfactory,當客戶程式設計師(client)需要乙個物件時候就會向 flyweightfactory 發出

請求物件的訊息 getflyweight()訊息,flyweightfactory 擁有乙個管理、儲存物件的「倉

庫」(或者叫物件池,vector 實現),getflyweight()訊息會遍歷物件池中的物件,如果已

經存在則直接返回給 client,否則建立乙個新的物件返回給 client。當然可能也有不想被共

享的物件(例如結構圖中的 unshareconcreteflyweight),但不在本模式的講解範圍,故在實

現中不給出。

舉個圍棋的例子,圍棋的棋盤共有361格,即可放361個棋子。現在要實現乙個圍棋程式,該怎麼辦呢?首先要考慮的是棋子棋盤的實現,可以定義乙個棋子的類,成員變數包括棋子的顏色、形狀、位置等資訊,另外再定義乙個棋盤的類,成員變數中有個容器,用於存放棋子的物件。下面給出**表示:

棋子的定義,當然棋子的屬性除了顏色和位置,還有其他的,這裡略去。這兩個屬性足以說明問題。

//

棋子顏色

enum

piececolor ;

//棋子位置

struct

piecepos

};//

棋子定義

class

piece

~piece() {}

virtual

void

draw() {}

};class blackpiece: public

piece

~blackpiece() {}

void draw()

};class whitepiece: public

piece

~whitepiece() {}

void draw()

};

棋盤的定義:

class

pieceboard

~pieceboard()

void setpiece(piececolor color, piecepos pos) //

一步棋,在棋盤上放一顆棋子

else

m_vecpiece.push_back(piece);

//加入容器中

}

void clear() //

釋放記憶體

};

客戶的使用方式如下:

int

main()

可以發現,棋盤的容器中存放了已下的棋子,而每個棋子包含棋子的所有屬性。一盤棋往往需要含上百顆棋子,採用上面這種實現,占用的空間太大了。如何改進呢?用享元模式。其定義為:運用共享技術有效地支援大量細粒度的物件。

在圍棋中,棋子就是大量細粒度的物件。其屬性有內在的,比如顏色、形狀等,也有外在的,比如在棋盤上的位置。內在的屬性是可以共享的,區分在於外在屬性。因此,可以這樣設計,只需定義兩個棋子的物件,一顆黑棋和一顆白棋,這兩個物件含棋子的內在屬性;棋子的外在屬性,即在棋盤上的位置可以提取出來,存放在單獨的容器中。相比之前的方案,現在容器中僅僅存放了位置屬性,而原來則是棋子物件。顯然,現在的方案大大減少了對於空間的需求。

關注pieceboard 的容器,之前是vectorm_vecpiece,現在是vectorm_vecpos。這裡是關鍵。

改進後的

棋子的新定義,只包含內在屬性:

//

棋子顏色

enum

piececolor ;

//棋子位置

struct

piecepos

};//

棋子定義

class

piece

~piece() {}

virtual

void

draw() {}

};class blackpiece: public

piece

~blackpiece() {}

void draw()

};class whitepiece: public

piece

~whitepiece() {}

void draw()

};

相應棋盤的定義為:

class

pieceboard

~pieceboard()

void

setpiece(piececolor color, piecepos pos)

else

m_vecpos.push_back(pos);}};

客戶的使用方式一樣,這裡不重複給出,現在給出享元模式的uml圖,以圍棋為例。棋盤中含兩個共享的物件,黑棋子和白棋子,所有棋子的外在屬性都存放在單獨的容器中。

uml類圖:

設計模式 11 享元模式

舉個圍棋的例子,圍棋的棋盤共有361格,即可放361個棋子。現在要實現乙個圍棋程式,該怎麼辦呢?首先要考慮的是棋子棋盤的實現,可以定義乙個棋子的類,成員變數包括棋子的顏色 形狀 位置等資訊,另外再定義乙個棋盤的類,成員變數中有個容器,用於存放棋子的物件。下面給出 表示 棋子的定義,當然棋子的屬性除了...

11 享元模式

一 享元模式 享元設計模式通過為相似物件引入資料共享來最小化記憶體使用,提公升效能。享元模式定義如下 使用共享物件支援大量細粒度物件。大量細粒度的物件的支援共享,可能會涉及這些物件的兩類資訊 內部狀態資訊和外部狀態資訊。內部狀態資訊就是可共享出來的資訊,它們儲存在享元物件內部,不會隨著特定環境的改變...

(11)享元模式

享元模式用於減少建立物件的數量,以減少記憶體占用和提高效能。享元模式嘗試重用現有的同類物件,如果未找到匹配的物件,則建立新物件。享元模式用得比較多的是池化技術,如常量池,執行緒池,連線池等等。import j a.util.hashmap import j a.util.map 享元模式 publi...