無為

          無為則可為,無為則至深!

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            190 Posts :: 291 Stories :: 258 Comments :: 0 Trackbacks

          一、 享元(Flyweight)模式(轉貼)

          Flyweight在拳擊比賽中指最輕量級,即"蠅量級",有些作者翻譯為"羽量級"。這里使用"享元模式"更能反映模式的用意。

          享元模式以共享的方式高效地支持大量的細粒度對象。享元對象能做到共享的關鍵是區分內蘊狀態(Internal State)和外蘊狀態(External State)。內蘊狀態是存儲在享元對象內部并且不會隨環境改變而改變。因此內蘊狀態并可以共享。

          外蘊狀態是隨環境改變而改變的、不可以共享的狀態。享元對象的外蘊狀態必須由客戶端保存,并在享元對象被創建之后,在需要使用的時候再傳入到享元對象內部。外蘊狀態與內蘊狀態是相互獨立的。

          享元模式的應用

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


          二、 單純享元模式的結構

          在單純享元模式中,所有的享元對象都是可以共享的。單純享元模式所涉及的角色如下:

          抽象享元(Flyweight)角色:此角色是所有的具體享元類的超類,為這些類規定出需要實現的公共接口。那些需要外蘊狀態(External State)的操作可以通過調用商業方法以參數形式傳入。

          具體享元(ConcreteFlyweight)角色:實現抽象享元角色所規定的接口。如果有內蘊狀態的話,必須負責為內蘊狀態提供存儲空間。享元對象的內蘊狀態必須與對象所處的周圍環境無關,從而使得享元對象可以在系統內共享的。

          享元工廠(FlyweightFactory)角色:本角色負責創建和管理享元角色。本角色必須保證享元對象可以被系統適當地共享。當一個客戶端對象調用一個享元對象的時候,享元工廠角色會檢查系統中是否已經有一個復合要求的享元對象。如果已經有了,享元工廠角色就應當提供這個已有的享元對象;如果系統中沒有一個適當的享元對象的話,享元工廠角色就應當創建一個合適的享元對象。

          客戶端(Client)角色:本角色需要維護一個對所有享元對象的引用。本角色需要自行存儲所有享元對象的外蘊狀態。


          三、 單純享元模式的示意性源代碼

          // Flyweight pattern -- Structural example  
          using System;
          using System.Collections;

          // "FlyweightFactory"
          class FlyweightFactory
          {
            
          // Fields
            private Hashtable flyweights = new Hashtable();

            
          // Constructors
            public FlyweightFactory()
            
          {
              flyweights.Add(
          "X"new ConcreteFlyweight());
              flyweights.Add(
          "Y"new ConcreteFlyweight());
              flyweights.Add(
          "Z"new ConcreteFlyweight());
            }


            
          // Methods
            public Flyweight GetFlyweight(string key)
            
          {
              
          return((Flyweight)flyweights[ key ]);
            }

          }


          // "Flyweight"
          abstract class Flyweight
          {
            
          // Methods
            abstract public void Operation( int extrinsicstate );
          }


          // "ConcreteFlyweight"
          class ConcreteFlyweight : Flyweight
          {
            
          private string intrinsicstate = "A";
            
          // Methods
            override public void Operation( int extrinsicstate )
            
          {
              Console.WriteLine(
          "ConcreteFlyweight: intrinsicstate {0}, extrinsicstate {1}"
                intrinsicstate, extrinsicstate );
            }

          }


          /// <summary>
          /// Client test
          /// </summary>

          public class Client
          {
            
          public static void Main( string[] args )
            
          {
              
          // Arbitrary extrisic state
              int extrinsicstate = 22;
               
              FlyweightFactory f 
          = new FlyweightFactory();

              
          // Work with different flyweight instances
              Flyweight fx = f.GetFlyweight("X");
              fx.Operation( 
          --extrinsicstate );

              Flyweight fy 
          = f.GetFlyweight("Y");
              fy.Operation( 
          --extrinsicstate );

              Flyweight fz 
          = f.GetFlyweight("Z");
              fz.Operation( 
          --extrinsicstate );
            }

          }


          四、 復合享元模式的結構

          單純享元模式中,所有的享元對象都可以直接共享。下面考慮一個較為復雜的情況,即將一些單純享元使用合成模式加以復合,形成復合享元對象。這樣的復合享元對象本身不能共享,但是它們可以分解成單純享元對象,而后者則可以共享。

          復合享元模式的類圖如下圖所示:

          享元模式所涉及的角色有抽象享元角色、具體享元角色、復合享元角色、享員工廠角色,以及客戶端角色等。

          抽象享元角色:此角色是所有的具體享元類的超類,為這些類規定出需要實現的公共接口。那些需要外蘊狀態(External State)的操作可以通過方法的參數傳入。抽象享元的接口使得享元變得可能,但是并不強制子類實行共享,因此并非所有的享元對象都是可以共享的。

          具體享元(ConcreteFlyweight)角色:實現抽象享元角色所規定的接口。如果有內蘊狀態的話,必須負責為內蘊狀態提供存儲空間。享元對象的內蘊狀態必須與對象所處的周圍環境無關,從而使得享元對象可以在系統內共享。有時候具體享元角色又叫做單純具體享元角色,因為復合享元角色是由單純具體享元角色通過復合而成的。

          復合享元(UnsharableFlyweight)角色:復合享元角色所代表的對象是不可以共享的,但是一個復合享元對象可以分解成為多個本身是單純享元對象的組合。復合享元角色又稱做不可共享的享元對象。

          享元工廠(FlyweightFactoiy)角色:本角色負責創建和管理享元角色。本角色必須保證享元對象可以被系統適當地共享。當一個客戶端對象請求一個享元對象的時候,享元工廠角色需要檢查系統中是否已經有一個符合要求的享元對象,如果已經有了,享元工廠角色就應當提供這個已有的享元對象;如果系統中沒有一個適當的享元對象的話,享元工廠角色就應當創建一個新的合適的享元對象。

          客戶端(Client)角色:本角色還需要自行存儲所有享元對象的外蘊狀態。

          注:由于復合享元模式比較復雜,這里就不再給出示意性代碼。通過將享元模式與合成模式組合在一起,可以確保復合享元中所包含的每個單純享元都具有相同的外蘊狀態,而這些單純享元的內蘊狀態往往不同。該部分內容可以參考《Java與模式》第31章內容。


          五、 一個咖啡攤的例子

          在這個咖啡攤(Coffee Stall)所使用的系統里,有一系列的咖啡"風味(Flavor)"。客人到攤位上購買咖啡,所有的咖啡均放在臺子上,客人自己拿到咖啡后就離開攤位。咖啡有內蘊狀態,也就是咖啡的風味;咖啡沒有環境因素,也就是說沒有外蘊狀態。如果系統為每一杯咖啡都創建一個獨立的對象的話,那么就需要創建出很多的細小對象來。這樣就不如把咖啡按照種類(即"風味")劃分,每一種風味的咖啡只創建一個對象,并實行共享。

          使用咖啡攤主的語言來講,所有的咖啡都可按"風味"劃分成如Capucino、Espresso等,每一種風味的咖啡不論賣出多少杯,都是全同、不可分辨的。所謂共享,就是咖啡風味的共享,制造方法的共享等。因此,享元模式對咖啡攤來說,就意味著不需要為每一份單獨調制。攤主可以在需要時,一次性地調制出足夠一天出售的某一種風味的咖啡。

          很顯然,這里適合使用單純享元模式。系統的設計如下:

          using System;
          using System.Collections;

          public abstract class Order
          {
            
          // 將咖啡賣給客人
            public abstract void Serve();
            
          // 返回咖啡的名字
            public abstract string GetFlavor();
          }


          public class Flavor : Order
          {
            
          private string flavor;

            
          // 構造函數,內蘊狀態以參數方式傳入
            public Flavor(string flavor)
            
          {
              
          this.flavor = flavor;
            }


            
          // 返回咖啡的名字
            public override string GetFlavor()
            
          {
              
          return this.flavor;
            }


            
          // 將咖啡賣給客人
            public override void Serve()
            
          {
              Console.WriteLine(
          "Serving flavor " + flavor);
            }

          }


          public class FlavorFactory
          {
            
          private Hashtable flavors = new Hashtable();

            
          public Order GetOrder(string key)
            
          {
              
          if(! flavors.ContainsKey(key))
                flavors.Add(key, 
          new Flavor(key));

                  
          return ((Order)flavors[key]);
            }


            
          public int GetTotalFlavorsMade()
            
          {
              
          return flavors.Count;
            }

          }


          public class Client
          {
            
          private static FlavorFactory flavorFactory;
            
          private static int ordersMade = 0;

            
          public static void Main( string[] args )
            
          {
              flavorFactory 
          = new FlavorFactory();

              TakeOrder(
          "Black Coffee");


          凡是有該標志的文章,都是該blog博主Caoer(草兒)原創,凡是索引、收藏
          、轉載請注明來處和原文作者。非常感謝。

          posted on 2006-02-16 09:04 草兒 閱讀(1273) 評論(1)  編輯  收藏 所屬分類: 設計模式

          Feedback

          # re: 享元(Flyweight)模式 2006-05-25 19:26 pc
          http://www.kpwang.com/pc/view.jsp?board_id=1&article_id=200645223821
          Java常見問題集錦(轉載)

          http://www.kpwang.com/pc/view.jsp?board_id=1&article_id=200645223641
          java中的易混問題收集

          http://www.kpwang.com/pc/view.jsp?board_id=1&article_id=20064522334
          Java學習過程的一些重點  回復  更多評論
            

          主站蜘蛛池模板: 普宁市| 志丹县| 铜川市| 海伦市| 枞阳县| 文安县| 通化县| 晋州市| 农安县| 日土县| 新龙县| 克什克腾旗| 汾阳市| 双牌县| 双城市| 黑水县| 南投县| 酒泉市| 霍山县| 富蕴县| 平湖市| 临颍县| 大关县| 宁南县| 汾阳市| 融水| 兴国县| 富锦市| 承德市| 高平市| 九江县| 太原市| 西贡区| 叙永县| 沙坪坝区| 余江县| 拉萨市| 临沭县| 滦平县| 民县| 梁河县|