一、概述
在軟件開發中,我們有時需要創建大量細粒度的對象,比如文檔處理系統就可能需要創建成千上萬的字符對象。但如果對每個字符對象都分配內存,那么在系統運行時就會耗費大量的內存。如何在保留面向對象操作方式優點的同時避免創建大量的對象呢?這就到了享元模式發揮作用的時候了。
二、享元模式
享元模式運用共享技術有效地支持大量細粒度的對象。例如可以對文檔處理系統創建共享池,在共享池中建立字母和代碼的對應關系,這樣就可以用共享池中的26個對象解決需要創建大量對象的問題。其結構圖如下:
Flyweight定義了享元接口,外部對象通過這個接口來訪問具體的享元對象。
ConcreteFlyweight實現Flyweight接口,定義了具體的享元對象,並保存享元對象的內部狀態。該享元對象是可共享的。
UnsharedConcreteFlyweight實現Flyweight接口,定義了不用於共享的享元對象。
FlyweightFactory創建並管理享元對象。
Client保存對享元接口的引用,通過該引用有效的使用具體的享元對象。
三、示例
我們簡單的實現本文開頭所表述的文檔處理系統。
首先定義Flyweight。
1 public abstract class Character 2 { 3 public int Size { get; set; } 4 public Color Color { get; set; } 5 protected char _c; 6 7 public Character() 8 { 9 Size = 10; 10 Color = Color.Black; 11 } 12 13 public override string ToString() 14 { 15 return string.Format("Character is {0}, Size is {1}, Color is {2}", _c, Size.ToString(), Color.ToString()); 16 } 17 }
然后實現具體的享元對象。
1 public class CharacterA : Character 2 { 3 public CharacterA() 4 { 5 _c = 'A'; 6 } 7 } 8 9 public class CharacterB : Character 10 { 11 public CharacterB() 12 { 13 _c = 'B'; 14 } 15 } 16 17 public class CharacterC : Character 18 { 19 public CharacterC() 20 { 21 _c = 'C'; 22 } 23 }
接着定義FlyweightFactory並建立共享池。
1 public static class CharacterFactory 2 { 3 private static Dictionary<char, Character> _characters; 4 5 static CharacterFactory() 6 { 7 _characters = new Dictionary<char, Character>(); 8 _characters.Add('a', new CharacterA()); 9 _characters.Add('b', new CharacterB()); 10 _characters.Add('c', new CharacterC()); 11 } 12 13 public static Character GetCharacter(char c) 14 { 15 return _characters[c]; 16 } 17 }
最后看一下如何使用這些享元對象。
1 static void Main(string[] args) 2 { 3 Character character = CharacterFactory.GetCharacter('a'); 4 Console.WriteLine(character.ToString()); 5 character = CharacterFactory.GetCharacter('b'); 6 character.Size = 20; 7 character.Color = Color.Red; 8 Console.WriteLine(character.ToString()); 9 character = CharacterFactory.GetCharacter('c'); 10 character.Size = 15; 11 character.Color = Color.Yellow; 12 Console.WriteLine(character.ToString()); 13 }