欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++設(shè)計(jì)模式編程之Flyweight享元模式結(jié)構(gòu)詳解

 更新時(shí)間:2016年03月16日 10:52:34   作者:夢(mèng)在天涯  
這篇文章主要介紹了C++設(shè)計(jì)模式編程的Flyweight享元模式結(jié)構(gòu),享元模式在實(shí)現(xiàn)過程中主要是要為共享對(duì)象提供一個(gè)存放的"倉庫"(對(duì)象池),需要的朋友可以參考下

由遇到的問題引出享元模式:

在面向?qū)ο笙到y(tǒng)的設(shè)計(jì)何實(shí)現(xiàn)中,創(chuàng)建對(duì)象是最為常見的操作。這里面就有一個(gè)問題:如果一個(gè)應(yīng)用程序使用了太多的對(duì)象,就會(huì)造成很大的存儲(chǔ)開銷。特別是對(duì)于大量輕量級(jí)(細(xì)粒度)的對(duì)象,比如在文檔編輯器的設(shè)計(jì)過程中,我們?nèi)绻麨闆]有字母創(chuàng)建一個(gè)對(duì)象的話,系統(tǒng)可能會(huì)因?yàn)榇罅康膶?duì)象而造成存儲(chǔ)開銷的浪費(fèi)。例如一個(gè)字母"a"在文檔中出現(xiàn)了100000 次,而實(shí)際上我們可以讓這一萬個(gè)字母"a"共享一個(gè)對(duì)象,當(dāng)然因?yàn)樵诓煌奈恢每赡茏帜?a"有不同的顯示效果(例如字體和大小等設(shè)置不同),在這種情況我們可以為將對(duì)象的狀態(tài)分為"外部狀態(tài)"和"內(nèi)部狀態(tài)",將可以被共享(不會(huì)變化)的狀態(tài)作為內(nèi)部狀態(tài)存儲(chǔ)在對(duì)象中,而外部對(duì)象(例如上面提到的字體、大小等)我們可以在適當(dāng)?shù)臅r(shí)候?qū)⑼獠繉?duì)象最為參數(shù)傳遞給對(duì)象(例如在顯示的時(shí)候,將字體、大小等信息傳遞給對(duì)象)。

作用:運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。

內(nèi)部狀態(tài)intrinsic和外部狀態(tài)extrinsic:

1)Flyweight模式中,最重要的是將對(duì)象分解成intrinsic和extrinsic兩部分。

2)內(nèi)部狀態(tài):在享元對(duì)象內(nèi)部并且不會(huì)隨環(huán)境改變而改變的共享部分,可以稱為是享元對(duì)象的內(nèi)部狀態(tài)

3)外部狀態(tài):而隨環(huán)境改變而改變的,取決于應(yīng)用環(huán)境,或是實(shí)時(shí)數(shù)據(jù),這些不可以共享的東西就是外部狀態(tài)了。

4)內(nèi)部狀態(tài)和外部狀態(tài)之間的區(qū)別:
  在Flyweight模式應(yīng)用中,通常修改的是外部狀態(tài)屬性,而內(nèi)部狀態(tài)屬性一般都是用于參考或計(jì)算時(shí)引用。
Flyweight執(zhí)行時(shí)所需的狀態(tài)必定是內(nèi)部的或外部的。內(nèi)部狀態(tài)存儲(chǔ)于ConcreteFlyweight對(duì)象之中;而外部狀態(tài)則由Client對(duì)象存儲(chǔ)或計(jì)算。當(dāng)用戶調(diào)用Flyweight對(duì)象的操作時(shí),將該狀態(tài)傳遞給它。

以文字處理軟件為例:

  內(nèi)部狀態(tài)存儲(chǔ)于flyweight中,它包含了獨(dú)立于flyweight場(chǎng)景的信息,這些信息使得flyweight可以被共享。如字符代碼,字符大小……

  外部狀態(tài)取決于flyweight場(chǎng)景,并根據(jù)場(chǎng)景而變化,因此不可共享。用戶對(duì)象負(fù)責(zé)在必要的時(shí)候?qū)⑼獠繝顟B(tài)傳遞給flyweight,如字符位置,字符顏色……

UML圖:

2016316105111376.png (656×489)

解析:
Flyweight:享元類的基類,定義一個(gè)接口,通過這個(gè)接口Flyweight可以接受并作用于外部狀態(tài)。

ConcreteFlyweight:實(shí)現(xiàn)Flyweight接口, 并為內(nèi)部狀態(tài)( 如果有的話) 增加存儲(chǔ)空間。ConcreteFlyweight對(duì)象必須是可共享的。它所存儲(chǔ)的狀態(tài)必須是內(nèi)部的(intrinsic);即,它必須獨(dú)立于ConcreteFlyweight對(duì)象的場(chǎng)景。

UnsharedConcreteFlyweight:并非所有的Flyweight子類都需要被共享。Flyweight接口使共享成為可能,但它并不強(qiáng)制共享。在Flyweight對(duì)象結(jié)構(gòu)的某些層次,UnsharedConcreteFlyweight對(duì)象通常將ConcreteFlyweight對(duì)象作為子節(jié)點(diǎn)。

FlyweightFactory:

1) 創(chuàng)建并管理Flyweight對(duì)象。

2)確保合理地共享Flyweight。當(dāng)用戶請(qǐng)求一個(gè)Flyweight時(shí),F(xiàn)lyweightFactory對(duì)象提供一個(gè)已創(chuàng)建的實(shí)例或者創(chuàng)建一個(gè)(如果不存在的話)

Client
1)維持一個(gè)對(duì)Flyweight的引用。

2)計(jì)算或存儲(chǔ)一個(gè)(多個(gè))Flyweight的外部狀態(tài)。

分析:
   享元模式可以避免大量非常相似類的開銷。在程序設(shè)計(jì)中,有時(shí)需要生成大量細(xì)粒度的類實(shí)例來表示數(shù)據(jù)。如果能發(fā)現(xiàn)這些實(shí)例數(shù)據(jù)除了幾個(gè)參數(shù)外基本都是相同的。有時(shí)就能夠大幅度地減少實(shí)例化的類的數(shù)量。如果能把那些參數(shù)移到類實(shí)例的外面,在方法調(diào)用時(shí)將它們傳遞進(jìn)來,就可以通過共享大幅度地減少單個(gè)實(shí)例的數(shù)目。

  比如在文檔編輯器的設(shè)計(jì)過程中,我們?nèi)绻麨闆]有字母創(chuàng)建一個(gè)對(duì)象的話,系統(tǒng)可能會(huì)因?yàn)榇罅康膶?duì)象而造成存儲(chǔ)開銷的浪費(fèi)。例如一個(gè)字母“a”在文檔中出現(xiàn)了100000次,而實(shí)際上我們可以讓這一萬個(gè)字母“a”共享一個(gè)對(duì)象,當(dāng)然因?yàn)樵诓煌奈恢每赡茏帜浮癮”有不同的顯示效果(例如字體和大小等設(shè)置不同),在這種情況我們可以為將對(duì)象的狀態(tài)分為“外部狀態(tài)”和“內(nèi)部狀態(tài)”,將可以被共享(不會(huì)變化)的狀態(tài)作為內(nèi)部狀態(tài)存儲(chǔ)在對(duì)象中,而外部對(duì)象(例如上面提到的字體、大小等)我們可以在適當(dāng)?shù)臅r(shí)候?qū)⑼獠繉?duì)象最為參數(shù)傳遞給對(duì)象(例如在顯示的時(shí)候,將字體、大小等信息傳遞給對(duì)象)。

  Flyweight的內(nèi)部狀態(tài)是用來共享的,F(xiàn)lyweightfactory負(fù)責(zé)維護(hù)一個(gè)Flyweight池(存放內(nèi)部狀態(tài)的對(duì)象),當(dāng)客戶端請(qǐng)求一個(gè)共享Flyweight時(shí),這個(gè)factory首先搜索池中是否已經(jīng)有可適用的,如果有,factory只是簡(jiǎn)單返回送出這個(gè)對(duì)象,否則,創(chuàng)建一個(gè)新的對(duì)象,加入到池中,再返回送出這個(gè)對(duì)象.池為重復(fù)或可共享的對(duì)象、屬性設(shè)置一個(gè)緩沖,稱為內(nèi)部狀態(tài)。這些內(nèi)部狀態(tài)一般情況下都是不可修改的,也就是在第一個(gè)對(duì)象、屬性被創(chuàng)建后,就不會(huì)去修改了(否則就沒意義了)。

  Flyweight 對(duì)對(duì)象的內(nèi)部狀態(tài)進(jìn)行共享,只為每種內(nèi)部狀態(tài)創(chuàng)建一個(gè)實(shí)例,對(duì)內(nèi)部狀態(tài)使用了單例模式。

  用戶不應(yīng)直接對(duì)ConcreteFlyweight類進(jìn)行實(shí)例化,而只能從FlyweightFactory對(duì)象得到ConcreteFlyweight對(duì)象,這可以保證對(duì)它們適當(dāng)?shù)剡M(jìn)行共享。

  存儲(chǔ)節(jié)約由以下幾個(gè)因素決定:
  1) 因?yàn)楣蚕?,?shí)例總數(shù)減少的數(shù)目
  2) 對(duì)象內(nèi)部狀態(tài)的平均數(shù)目
  3) 外部狀態(tài)是計(jì)算的還是存儲(chǔ)的

實(shí)現(xiàn)要點(diǎn)
1)享元工廠維護(hù)一張享元實(shí)例表。

2)享元不可共享的狀態(tài)需要在外部維護(hù)。即刪除外部狀態(tài):該模式的可用性在很大程度上取決于是否容易識(shí)別外部狀態(tài)并將它從共享對(duì)象中刪除。

3)按照需求可以對(duì)享元角色進(jìn)行抽象。

4)管理共享對(duì)象:引用計(jì)數(shù)和垃圾回收……

何時(shí)采用
1)如果一個(gè)應(yīng)用程序使用了大量的對(duì)象,而大量的這些對(duì)象造成了很大的存儲(chǔ)開銷時(shí)就應(yīng)該考慮使用;

2)還有就是對(duì)象的大多數(shù)狀態(tài)可變?yōu)橥獠繝顟B(tài),如果刪除對(duì)象的外部狀態(tài),那么可以用相對(duì)較少的共享對(duì)象取代很多組對(duì)象,此時(shí)可以考慮所使用享元模式。

3)系統(tǒng)中有大量耗費(fèi)了大量?jī)?nèi)存的細(xì)粒度對(duì)象,并且對(duì)外界來說這些對(duì)沒有任何差別的(或者說經(jīng)過改造后可以是沒有差別的)。

  在文檔編輯器例子中如果一個(gè)字符對(duì)應(yīng)一個(gè)對(duì)象,那么一篇文檔所要容納的對(duì)象將是非常的龐大耗費(fèi)大量的內(nèi)存。而實(shí)際組成文檔的字符是有限的,是由這些字符不同的組合和排列得到的。所以需要共享,將基本的字符進(jìn)行共享,將使得字符對(duì)象變得有限。

示例:
享元模式在編輯器系統(tǒng)中大量使用。一個(gè)文本編輯器往往會(huì)提供很多種字體,而通常的做法就是將每一個(gè)字母做成一個(gè)享元對(duì)象。享元對(duì)象的內(nèi)蘊(yùn)狀態(tài)就是這個(gè)字母,而字母在文本中的位置和字模風(fēng)格等其他信息則是外蘊(yùn)狀態(tài)。比如,字母a可能出現(xiàn)在文本的很多地方,雖然這些字母a的位置和字模風(fēng)格不同,但是所有這些地方使用的都是同一個(gè)字母對(duì)象。這樣一來,字母對(duì)象就可以在整個(gè)系統(tǒng)中共享。

// Flyweight pattern -- Real World example 


using System;
using System.Collections;

namespace DoFactory.GangOfFour.Flyweight.RealWorld
{

 // MainApp test application 

 class MainApp
 {
  static void Main()
  {
   // Build a document with text 
   string document = "AAZZBBZB";
   char[] chars = document.ToCharArray();

   CharacterFactory f = new CharacterFactory();

   // extrinsic state 
   int pointSize = 10;

   // For each character use a flyweight object 
   foreach (char c in chars)
   {
    pointSize++;
    Character character = f.GetCharacter(c);
    character.Display(pointSize);
   }

   // Wait for user 
   Console.Read();
  }
 }

 // "FlyweightFactory" 

 class CharacterFactory
 {
  private Hashtable characters = new Hashtable();

  public Character GetCharacter(char key)
  {
   // Uses "lazy initialization" 
   Character character = characters[key] as Character;
   if (character == null)
   {
    switch (key)
    {
     case 'A': character = new CharacterA(); break;
     case 'B': character = new CharacterB(); break;
      // 
     case 'Z': character = new CharacterZ(); break;
    }
    characters.Add(key, character);
   }
   return character;
  }
 }

 // "Flyweight" 

 abstract class Character
 {
  protected char symbol;
  protected int width;
  protected int height;
  protected int ascent;
  protected int descent;
  protected int pointSize;

  public abstract void Display(int pointSize);
 }

 // "ConcreteFlyweight" 

 class CharacterA : Character
 {
  // Constructor 
  public CharacterA()
  {
   this.symbol = 'A';
   this.height = 100;
   this.width = 120;
   this.ascent = 70;
   this.descent = 0;
  }

  public override void Display(int pointSize)
  {
   this.pointSize = pointSize;
   Console.WriteLine(this.symbol + 
    " (pointsize " + this.pointSize + ")");
  }
 }

 // "ConcreteFlyweight" 

 class CharacterB : Character
 {
  // Constructor 
  public CharacterB()
  {
   this.symbol = 'B';
   this.height = 100;
   this.width = 140;
   this.ascent = 72;
   this.descent = 0;
  }

  public override void Display(int pointSize)
  {
   this.pointSize = pointSize;
   Console.WriteLine(this.symbol + 
    " (pointsize " + this.pointSize + ")");
  }

 }

 // C, D, E, etc. 

 // "ConcreteFlyweight" 

 class CharacterZ : Character
 {
  // Constructor 
  public CharacterZ()
  {
   this.symbol = 'Z';
   this.height = 100;
   this.width = 100;
   this.ascent = 68;
   this.descent = 0;
  }

  public override void Display(int pointSize)
  {
   this.pointSize = pointSize;
   Console.WriteLine(this.symbol + 
    " (pointsize " + this.pointSize + ")");
  }
 }
}

Output:

2016316105157984.png (748×133)

享元模式的優(yōu)點(diǎn)和缺點(diǎn)

享元模式的優(yōu)點(diǎn)在于它大幅度地降低內(nèi)存中對(duì)象的數(shù)量。但是,它做到這一點(diǎn)所付出的代價(jià)也是很高的:
享元模式使得系統(tǒng)更加復(fù)雜。為了使對(duì)象可以共享,需要將一些狀態(tài)外部化,這使得程序的邏輯復(fù)雜化。
享元模式將享元對(duì)象的狀態(tài)外部化,而讀取外部狀態(tài)使得運(yùn)行時(shí)間稍微變長(zhǎng)。

相關(guān)文章

  • C 語言中strstr函數(shù)實(shí)例詳解

    C 語言中strstr函數(shù)實(shí)例詳解

    這篇文章主要介紹了C 語言中strstr函數(shù)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • C++ explicit關(guān)鍵字講解

    C++ explicit關(guān)鍵字講解

    這篇文章主要介紹了C++ explicit關(guān)鍵字講解,++提供了explicit關(guān)鍵字,相對(duì)于implicit而言,他默認(rèn)關(guān)閉了隱式類型轉(zhuǎn)換方法。至于兩者有什么區(qū)別,看下面文章內(nèi)容的介紹吧
    2021-12-12
  • c++報(bào)錯(cuò)問題解決方案lvalue required as left operand of assignment

    c++報(bào)錯(cuò)問題解決方案lvalue required as left opera

    這篇文章主要介紹了c++報(bào)錯(cuò):lvalue required as left operand of assignment,出現(xiàn)此錯(cuò)誤原因,是因?yàn)椋忍?hào)左邊是不可被修改的表達(dá)式或常量,而表達(dá)式或常量不能作為左值,需要的朋友可以參考下
    2023-01-01
  • C語言編程中借助pthreads庫進(jìn)行多線程編程的示例

    C語言編程中借助pthreads庫進(jìn)行多線程編程的示例

    這篇文章主要介紹了C語言編程中借助pthreads庫進(jìn)行多線程編程的示例,文中的示例環(huán)境為Windows系統(tǒng),需要的朋友可以參考下
    2015-11-11
  • C語言實(shí)現(xiàn)拼圖游戲源碼

    C語言實(shí)現(xiàn)拼圖游戲源碼

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)拼圖游戲源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • 深入理解數(shù)組指針與指針數(shù)組的區(qū)別

    深入理解數(shù)組指針與指針數(shù)組的區(qū)別

    本篇文章是對(duì)數(shù)組指針與指針數(shù)組的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 淺談c++調(diào)用python鏈接的問題及解決方法

    淺談c++調(diào)用python鏈接的問題及解決方法

    下面小編就為大家?guī)硪黄獪\談c++調(diào)用python鏈接的問題及解決方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-03-03
  • 徹底掌握C語言strcpy函數(shù)的用法

    徹底掌握C語言strcpy函數(shù)的用法

    C語言中的strcpy函數(shù),是一種C語言的標(biāo)準(zhǔn)庫函數(shù),它用于對(duì)字符串進(jìn)行復(fù)制。本章帶你了解它的使用并模擬實(shí)現(xiàn)它
    2022-05-05
  • va_list(),va_start(),va_arg(),va_end() 詳細(xì)解析

    va_list(),va_start(),va_arg(),va_end() 詳細(xì)解析

    這些宏定義在stdarg.h中,所以用到可變參數(shù)的程序應(yīng)該包含這個(gè)頭文件.下面我們寫一個(gè)簡(jiǎn)單的可變參數(shù)的函數(shù),該函數(shù)至少有一個(gè)整數(shù)參數(shù),第二個(gè)參數(shù)也是整數(shù),是可選的.函數(shù)只是打印這兩個(gè)參數(shù)的值
    2013-09-09
  • C++11右值引用和std::move語句實(shí)例解析(推薦)

    C++11右值引用和std::move語句實(shí)例解析(推薦)

    右值引用(及其支持的Move語意和完美轉(zhuǎn)發(fā))是C++0x將要加入的最重大語言特性之一。這篇文章主要介紹了C++11右值引用和std::move語句實(shí)例解析,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03

最新評(píng)論