设计模式(十)享元模式Flyweight(结构型)
?
1. 概述
面向?qū)ο蠹夹g(shù)可以很好地解決系統(tǒng)一些靈活性或可擴(kuò)展性或抽象性的問題,但在很多情況下需要在系統(tǒng)中增加類和對(duì)象的個(gè)數(shù)。當(dāng)對(duì)象數(shù)量太多時(shí),將導(dǎo)致運(yùn)行代價(jià)過高,帶來性能下降等問題。比如:
例子1:圖形應(yīng)用中的圖元等對(duì)象、字處理應(yīng)用中的字符對(duì)象等。
2.解決方案:
? ? ? ? ? 享元模式(Flyweight):對(duì)象結(jié)構(gòu)型模式運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。
? ? ? ? 它使用共享物件,用來盡可能減少內(nèi)存使用量以及分享資訊給盡可能多的相似物件;它適合用于當(dāng)大量物件只是重復(fù)因而導(dǎo)致無法令人接受的使用大量?jī)?nèi)存。通常物件中的部分狀態(tài)是可以分享。常見做法是把它們放在外部數(shù)據(jù)結(jié)構(gòu),當(dāng)需要使用時(shí)再將它們傳遞給享元。
?
4. 適用性
1)一個(gè)應(yīng)用程序使用大量相同或者相似的對(duì)象,造成很大的存儲(chǔ)開銷。
2)對(duì)象的大部分狀態(tài)都可以外部化,可以將這些外部狀態(tài)傳入對(duì)象中。
3)如果刪除對(duì)象的外部狀態(tài),那么可以用相對(duì)較少的共享對(duì)象取代很多組對(duì)象。
4)?應(yīng)用程序不依賴于對(duì)象標(biāo)識(shí)。由于Flyweight對(duì)象可以被共享,對(duì)于概念上明顯有別的對(duì)象,標(biāo)識(shí)測(cè)試將返回真值。
5)使用享元模式需要維護(hù)一個(gè)存儲(chǔ)享元對(duì)象的享元池,而這需要耗費(fèi)資源,因此,應(yīng)當(dāng)在多次重復(fù)使用享元對(duì)象時(shí)才值得使用享元模式
5.結(jié)構(gòu)
6.構(gòu)建模式的組成
1) 抽象享元類(Flyweight): 描述一個(gè)接口,通過這個(gè)接口flyweight可以接受并作用于外部狀態(tài)。
2) 具體享元類(ConcreteFlyweight):實(shí)現(xiàn)Flyweight接口 ,并為內(nèi)部狀態(tài)( 如果有的話 )增加存儲(chǔ)空間 。ConcreteFlyweight對(duì)象必須是可共享的。它所存儲(chǔ)的狀態(tài)必須是內(nèi)部的;即,它必須獨(dú)立于ConcreteFlyweight對(duì)象的場(chǎng)景。
3) 非共享具體享元類(UnsharedConcreteFlyweight):— 并非所有的Flyweight子類都需要被共享。Flyweight接口使共享成為可能,但它并不強(qiáng)制共享。在Flyweight對(duì)象結(jié)構(gòu)的某些層次,UnsharedConcreteFlyweight對(duì)象通常將ConcreteFlyweight對(duì)象作為子節(jié)點(diǎn)。
4) 享元工廠類(FlyweightFactory):創(chuàng)建并管理flyweight對(duì)象, 確保合理地共享flyweight。本角色必須保證享元對(duì)象可以被系統(tǒng)適當(dāng)?shù)毓蚕怼.?dāng)一個(gè)客戶端對(duì)象調(diào)用一個(gè)享元對(duì)象 ? flyweight的時(shí)候,享元工廠角色(Flyweight Factory對(duì)象)會(huì)檢查系統(tǒng)中是否已經(jīng)有一個(gè)符合要求的享元對(duì)象。如果已經(jīng)有了,享元工廠角色就應(yīng)當(dāng)提供這個(gè)已有的享元對(duì)象;如果系統(tǒng)中沒有一個(gè)適當(dāng)?shù)南碓獙?duì)象的話,享元工廠角色就應(yīng)當(dāng)創(chuàng)建一個(gè)合適的享元對(duì)象。
5)客戶(Client):維持一個(gè)對(duì)flyweight的引用。計(jì)算或存儲(chǔ)一個(gè)(多個(gè))flyweight的外部狀態(tài)。
7. 效果
?
享元模式的優(yōu)點(diǎn): 1)享元模式的優(yōu)點(diǎn)在于它可以極大減少內(nèi)存中對(duì)象的數(shù)量,使得相同對(duì)象或相似對(duì)象在內(nèi)存中只保存一份。 2)享元模式的外部狀態(tài)相對(duì)獨(dú)立,而且不會(huì)影響其內(nèi)部狀態(tài),從而使得享元對(duì)象可以在不同的環(huán)境中被共享。 享元模式的缺點(diǎn): 1)享元模式使得系統(tǒng)更加復(fù)雜,需要分離出內(nèi)部狀態(tài)和外部狀態(tài),這使得程序的邏輯復(fù)雜化。 2)為了使對(duì)象可以共享,享元模式需要將享元對(duì)象的狀態(tài)外部化,而讀取外部狀態(tài)使得運(yùn)行時(shí)間變長(zhǎng)。 8.實(shí)現(xiàn) 享元模式可以分成單純享元模式和復(fù)合享元模式兩種形式。【單純享元模式】
在單純的享元模式中,所有的享元對(duì)象都是可以共享的。源代碼:
?
[php]?view plaincopy print?【復(fù)合享元模式】
復(fù)合享元模式對(duì)象是由一些單純享元使用合成模式加以復(fù)合而成
復(fù)合享元角色所代表的對(duì)象是不可以共享的,但是一個(gè)復(fù)合享元對(duì)象可以分解成為多個(gè)本身是單純享元對(duì)象的組合。
?
?
[php]?view plaincopy print??
9. 與其他相關(guān)模式
客戶端要引用享元對(duì)象,是通過工廠對(duì)象創(chuàng)建或者獲得的,客戶端每次引用一個(gè)享元對(duì)象,都是可以通過同一個(gè)工廠對(duì)象來引用所需要的享元對(duì)象。因此,可以將享元工廠設(shè)計(jì)成單例模式,這樣就可以保證客戶端只引用一個(gè)工廠實(shí)例。因?yàn)樗械南碓獙?duì)象都是由一個(gè)工廠對(duì)象統(tǒng)一管理的,所以在客戶端沒有必要引用多個(gè)工廠對(duì)象。不管是單純享元模式還是復(fù)合享元模式中的享元工廠角色,都可以設(shè)計(jì)成為單例模式,對(duì)于結(jié)果是不會(huì)有任何影響的。
? ? ? ?Composite模式:Flyweight模式通常和Composite 模式結(jié)合起來,用共享葉結(jié)點(diǎn)的有向無環(huán)圖實(shí)現(xiàn)一個(gè)邏輯上的層次結(jié)構(gòu)。復(fù)合享元模式實(shí)際上是單純享元模式與合成模式的組合。單純享元對(duì)象可以作為樹葉對(duì)象來講,是可以共享的,而復(fù)合享元對(duì)象可以作為樹枝對(duì)象,?因此在復(fù)合享元角色中可以添加聚集管理方法。通常,最好用Flyweight實(shí)現(xiàn)State 和Strategy 對(duì)象。
10.總結(jié)
?
1) ?享元模式是一個(gè)考慮系統(tǒng)性能的設(shè)計(jì)模式,通過使用享元模式可以節(jié)約內(nèi)存空間,提高系統(tǒng)的性能。? 2) ?享元模式的核心在于享元工廠類,享元工廠類的作用在于提供一個(gè)用于存儲(chǔ)享元對(duì)象的享元池,用戶需要對(duì)象時(shí),首先從享元池中獲取,如果享 元池中不存在,則創(chuàng) ? ? ? 建一個(gè)新的享元對(duì)象返回給用戶,并在享元池中保存該新增對(duì)象。 3) ??享元模式以共享的方式高效地支持大量的細(xì)粒度對(duì)象,享元對(duì)象能做到共享的關(guān)鍵是區(qū)分內(nèi)部狀態(tài)(Internal State)和外部狀態(tài)(External State)。 (1) ??內(nèi)部狀態(tài)是存儲(chǔ)在享元對(duì)象內(nèi)部并且不會(huì)隨環(huán)境改變而改變的狀態(tài),因此內(nèi)部狀態(tài)可以共享。 (2) ??外部狀態(tài)是隨環(huán)境改變而改變的、不可以共享的狀態(tài)。享元對(duì)象的外部狀態(tài)必須由客戶端保存,并在享元對(duì)象被創(chuàng)建之后,在需要使用的時(shí)候 再傳入到享元對(duì) ? ? ? ? ? ? ? 象內(nèi)部。一個(gè)外部狀態(tài)與另一個(gè)外部狀態(tài)之間是相互獨(dú)立的。?
?
總結(jié)
以上是生活随笔為你收集整理的设计模式(十)享元模式Flyweight(结构型)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql中的时间函数---运维常用
- 下一篇: EF 与存储过程