基於面向對象思想設計的應用程序有時遇到須要場景大量相同或顯示對象實例的場景,這些數量龐大的實例極可能會消耗不少系統資源,最直接的就是內存了。好比要一款圍棋遊戲,若是每次落子都新建一個對象,將會佔用大量內存,而實際上棋子只有黑白兩色,不一樣的只是落子位置而已。另外,大量的主動型對象還會佔用不少CPU和顯卡的計算資源,舉個極端的例子,某個遊戲的沙漠場景,爲了使遊戲具備豐富的視覺效果,要求每一粒沙子都要隨着光線而有不一樣的呈現效果不一樣,這時候直接new固然也是不現實的。設計模式
享元模式提供了一種針對這類場景的解決方案。它經過共享已經存在的對象來大幅度減小須要建立的對象數量、避免大量類似對象的開銷,從而提升系統資源的利用率,支持大量細粒度對象的複用。緩存
UML類圖:
ide
代碼實現this
public abstract class Flyweight { //內部狀態 public string Instrinsic { get; set; } //外部狀態 protected string Extrinsic { get; set; } public Flyweight(string extrinsic) { this.Extrinsic = extrinsic; } //定義業務操做 public abstract void Operate(int id); } public class ConcreteFlyweight : Flyweight { //接受外部狀態 public ConcreteFlyweight(String extrinsic) : base(extrinsic) { } //根據外部狀態進行邏輯處理 public override void Operate(int id) { Console.WriteLine("Flyweight:" + id); } } public class UnsharedConcreteFlyweight : Flyweight { public UnsharedConcreteFlyweight(String extrinsic) : base(extrinsic) { } public override void Operate(int id) { Console.WriteLine("不共享的Flyweight:" + id); } } public class FlyweightFactory { //定義一個池容器 private static Dictionary<String, Flyweight> pool = new Dictionary<String, Flyweight>(); //享元工廠 public static Flyweight GetFlyweight(string extrinsic) { Flyweight flyweight = null; if (pool.ContainsKey(extrinsic)) { flyweight = pool[extrinsic]; Console.Write($"已有{extrinsic} "); } else { flyweight = new ConcreteFlyweight(extrinsic); pool.Add(extrinsic, flyweight); Console.Write($"新建{extrinsic} "); } return flyweight; } }
享元模式的核心是用一個池容器來緩存須要共享的對象,C#能夠用Dictionary來實現。設計
內部狀態與外部狀態
因爲這些數量較大的細粒度對象有着相近的性質,爲了能共享這些對象,須要將這些對象的信息分爲兩個部分:內部狀態和外部狀態。code
圍棋例子的誤導
使用圍棋這個例子會容易讓人產生一個困惑:既然實際上只有兩個對象(黑、白),那麼是如何讓同一個對象即出如今位置A,又出如今位置B的呢?難不成像薛定諤的貓那樣,能夠有多種狀態?
實際上這裏所謂的共享對象,共享的應該是對象的行爲。在圍棋遊戲中能夠理解爲,在畫布上繪製的棋子圖案。每一個棋子對象都有個繪製棋子圖案的行爲,經過設置不一樣的外部狀態(落子位置),就棋子的繪圖行爲就會在畫布上不一樣的位置繪製圖案。對象
優勢blog
參考書籍:
王翔著 《設計模式——基於C#的工程化實現及擴展》遊戲