享元模式

壹頁書發表於2017-03-29

原理:

     運用共享技術有效地支援大量細粒度的物件。

不使用享元模式:

 class Game  //遊戲
    {
        private string name = "";
        public Game(string name)
        {
            this.name = name;
        }

        public void Play()
        {
            Console.WriteLine("執行遊戲:" + name);
        }
    }

static void Main(string[] args)
        {
            Game zs = new Game("鬥地主");
            zs.Play();

            Game ls = new Game("鬥地主");
            ls.Play();

            Game ww = new Game("鬥地主");
            ww.Play();

            Game zl = new Game("麻將");
            zl.Play();

            Game sq = new Game("麻將");
            sq.Play();

            Game zb = new Game("麻將");
            zb.Play();

            Console.Read();
        }
三個鬥地主例項,本質都是一樣的程式碼,但是隨著使用者增多,例項也會增多,對伺服器資源造成浪費,希望共享程式碼



abstract class Game   //遊戲
    {
        public abstract void Play();
    }

    //具體的遊戲
    class ConcreteGame : Game
    {
        private string name = "";
        public ConcreteGame(string name)
        {
            this.name = name;
        }

        public override void Play()
        {
            Console.WriteLine("執行遊戲:" + name);
        }
    }
   class GameFactory   //遊戲工廠
   {
        private Hashtable flyweights = new Hashtable();

        //獲得遊戲分類
        public Game GetGameCategory(string key)
        {
            if (!flyweights.ContainsKey(key))
                flyweights.Add(key, new ConcreteGame(key));
            return ((Game)flyweights[key]);
        }

        //獲得遊戲分類總數
        public int GetGameCount()
        {
            return flyweights.Count;
        }
   }
        static void Main(string[] args)
        {

            GameFactory f = new GameFactory();

            Game zs = f.GetGameCategory("鬥地主");
            zs.Play();
            Game ls = f.GetGameCategory("鬥地主");
            ls.Play();
            Game ww = f.GetGameCategory("鬥地主");
            ww.Play();
            Game zl = f.GetGameCategory("麻將");
            zl.Play();
            Game sq = f.GetGameCategory("麻將");
            sq.Play();
            Game zb = f.GetGameCategory("麻將");
            zb.Play();
            Console.WriteLine("遊戲邏輯總數為 {0}", f.GetGameCount());

            Console.Read();
        }


內部狀態與外部狀態

(1)上述程式碼實現了享元模式共享的目的,無論幾個使用者,執行遊戲一樣,就只保留一個遊戲邏輯程式碼。
(2)但是,這些使用者畢竟不是同一個使用者,使用者名稱不同,使用者的牌也不同。

(3)我們稱享元物件內部不隨環境變化的共享部分稱為內部狀態。
(4)而隨環境而改變,不可以共享的稱為外部狀態。


   //使用者
    public class User
    {
        private string name;

        public User(string name)
        {
            this.name = name;
        }

        public string Name
        {
            get { return name; }
        }
    }

abstract class Game   //遊戲
    {
        public abstract void Play(User user);
    }

    //具體的遊戲
    class ConcreteGame : Game
    {
        private string name = "";
        public ConcreteGame(string name)
        {
            this.name = name;
        }

        public override void Play(User user)
        {
            Console.WriteLine("執行遊戲:" + name + " 使用者:" + user.Name);
        }
    }
 static void Main(string[] args)
        {
            GameFactory f = new GameFactory();

            Game zs = f.GetGameCategory("鬥地主");
            zs.Play(new User("張三"));
            Game ls = f.GetGameCategory("鬥地主");
            ls.Play(new User("李四"));
            Game ww = f.GetGameCategory("鬥地主");
            ww.Play(new User("王五"));
            Game zl = f.GetGameCategory("麻將");
            zl.Play(new User("趙六"));
            Game sq = f.GetGameCategory("麻將");
            sq.Play(new User("孫七"));
            Game zb = f.GetGameCategory("麻將");
            zb.Play(new User("周八"));

            Console.WriteLine("遊戲邏輯總數為 {0}", f.GetGameCount());

            Console.Read();
        }
優缺點:

享元模式的優點在於它大幅度地降低記憶體中物件的數量。但是,它做到這一點所付出的代價也是很高的,享元模式使得系統更加複雜。 
為了使物件可以共享,需要將一些狀態外部化,這使得程式的邏輯複雜化。


應用:

享元模式在編輯器軟體中大量使用,如在一個文件中多次出現相同的圖片,則只需要建立一個圖片物件,通過在應用程式中設定該圖片出現的位置,可以實現該圖片在不同地方多次重複顯示。

相關文章