設計模式-單例模式,觀察者模式

張龍豪發表於2014-08-15

序言

點選檢視:設計模式系列

咳咳,今天起,我要把對設計模式的理解心得,用全新的案例去分析,分享給大家。希望大家能夠喜歡。

觀察者模式

舉例闡述:遊戲情節,一顆小男孩,丟到眾多鬼子附近,爆炸啦,根據炸彈的威力計算爆炸後鬼子的血量,假定有些鬼子有防具,有些鬼子沒有防具。

分析:這種情況,使用觀察者模式是比較理想的,因為觀察者模式的就是是處理物件間一對多的依賴關係的,當一個物件發生變化,其它依賴他的物件都要得到通知並更新。

定義:在觀察者模式中,上述小男孩被稱為主題,而小鬼子們就被稱為觀察者。

下面我用程式碼,把舉例給演示出來。

定義觀察者模式中的主題。

   //炸彈
    public class bomb
    { 
        //炸彈名稱
        public  string Name;
        //炸彈攻擊距離
        public  int Length;
        //炸彈攻擊力
        public int ATK;
        //簡單期間,這裡炸彈我只有一顆啦。
        public bomb()
        {
            Name = "小男孩";
            Length = 100;
            ATK = 1000;
        }

        public DeBeng debeng;

        //爆炸
        public void beng()
        {
            if (debeng != null)
            {
                debeng(this);
            }
        }
    }
   
    //定義委託,為啦新增爆炸影響的路人
    public delegate void DeBeng(bomb bomb);

定義觀察者模式中的觀察者

//觀察者,路人
    public class roadPeople
    { 
        //離炸彈距離
        public  int Length;
        //路人名稱
        public  string Name;
        //血量
        public int LifeLength;
        //盾抵抗力
        public int ShieldLth;
        /// <summary>
        /// 初始化路人
        /// </summary>
        /// <param name="name">名稱</param>
        /// <param name="lgth">炸彈距離</param>
        /// <param name="llth">生命值</param>
        /// <param name="sth">抵抗能力</param>
        public roadPeople(string name, int lgth,int llth,int sth)
        {
            Length = lgth;
            Name = name;
            LifeLength = llth;
            ShieldLth = sth;
        }
        //被炸,這裡的處理方法我寫一致啦,其實可以是根據不同的櫃子有不一樣的處理方式,這樣就展示啦觀察者模式的強大,我這裡為啦簡便起見,就沒有定義那麼多類
        public void Beated(bomb bom)   
        {
            //盾削去攻擊
            int th=this.ShieldLth-bom.ATK;
            //被炸後,血量情況
            string info="";
            if (th > 0)
            { 
                //盾牛逼,不掉血
                info = "我是:" + this.Name + "。我的盾更牛逼不掉血" ;               
            }
            else
            {
                //掉血
                int h=th+this.LifeLength;
                //判斷死亡
                if (h>0)
                {
                    //未死
                    info = "我是:" + this.Name + "。掉血:" + (-th)+"點。";
                }
                else
                {
                    //已死
                    info = "我是:" + this.Name + "。最後一句話,但願蒼老師隨我而去!";
                }
            }
            Console.WriteLine("啊,哦,額,噗,我靠,牛逼。"+ info);
        }
    }

使用主題與觀察者

static void Main()
        {
           //路人集合
            List<roadPeople> list = new List<roadPeople>() { 
           //路人甲,距離炸彈10米,血量100,帶1級盾
            new roadPeople("路人甲",40,100,1),
            //路人乙,距離炸彈20米,血量1000,帶10級盾
            new roadPeople("路人乙",40,100,4000),
            new roadPeople("路人丙",50,2000,50),
            new roadPeople("路人丁",1000,30,1)         
           };

            //例項化炸彈
            bomb bom = new bomb();
            //新增能炸到的路人
            foreach(roadPeople rp in list)
            {
                if ((bom.Length - rp.Length) > 0)
                {
                    bom.debeng += new DeBeng(rp.Beated);                    
                }
            }
            //炸彈爆炸
            bom.beng();
            Console.ReadLine();
        }

執行結果

簡單闡述構建使用觀察者模式過程:主題可變更做為引數,觀察者擁有自己的屬性與同樣簽名的響應方法,把各個觀察者物件的被炸方法新增到事件中,然後把主題物件作為引數傳遞給事件中,這樣就能根據觀察者各自的屬性,與計算方法來獲取通知更新。

觀察者模式的效果:觀察者促進啦主體的抽象耦合。主體不知道觀察者的細節,觀察者可根據自身的屬性功能來對主題的通知做變更。然而觀察者也有自己的缺點,就是當主題發生一系列的變化事,觀察者都要做批量的更新,如果這樣的更新成本很高,那麼解決方法就是根據種類需求通知,而不能盲目的通知所有的觀察者。

單例模式(單件模式)

案例:你只有一個老爸,你媽只有一個老公,然而他是同一個人,晚上你們吃過飯,你就讓你爸給你講你小時候的事,你媽讓你爸講她們談戀愛時候的事,老爸說除啦你們兩個其它人是沒有這待遇的。

分析:這種情況下,老爸只有一個,不能多次建立,就很適合使用單例模式。

單例模式:首先要確定老爸不能被多次建立,因為老爸只有一個,使我們的唯一。

單例模式中的單件確保類有且僅有一個

 //單例中的Dad有且僅有一個
    public class Dad
    {
        //老爸
        static Dad dad = null;
        static readonly object padlock = new object();
        Dad()
        {
            //吃飽,先休息2秒
            Thread.Sleep(2000);
        }

        ///故事內容
        private string content = "";
        ///講故事 
        public void  tell()
        {
            lock (padlock)
            {
                if (Thread.CurrentThread.Name == "mama")
                {
                    content = "老婆那畫面太美,我不敢想!";
                }
                else if (Thread.CurrentThread.Name == "me")
                {
                    content = "兒子,你小時候最乖啦,我們都很愛你。";
                }
                else
                {
                    content = "除來老婆和孩子,別人休想讓我講故事!";
                }
            }
        }

        ///獲得故事內容
        public string GetCounter()
        {
            return content;
        }

        //老爸只有一個,不能被多次建立,叫一下老爸,老爸就會出現
        public static Dad sayDad
        {
            get
            {
                if (dad == null)
                {
                    lock (padlock)
                    {
                        if (dad == null)
                        {
                            dad = new Dad();
                        }
                    }
                }
                return dad;
            }
        }
    }

使用單件物件

 /// <summary>
        /// 執行緒工作
        /// </summary>
        public static void DoSomeWork()
        {
            ///構造顯示字串
            string results = "";

            ///叫一下老爸,唯一的老爸閃亮登場
            Dad dad = Dad.sayDad;

            ///開始講故事
            dad.tell();

            results += "講給";
            results += Thread.CurrentThread.Name.ToString() + "——〉";
            results += "我想對你說:";
            results += dad.GetCounter().ToString();
            results += "\n";
            Console.WriteLine(results);

            ///清空顯示字串
            results = "";


        }

        //爸爸的世界裡,永遠有媽媽跟我2個執行緒
        public void StartMain()
        {
            Thread thread0 = Thread.CurrentThread;
            thread0.Name = "me";
            Thread thread1 = new Thread(new ThreadStart(DoSomeWork));
            thread1.Name = "mama";
            Thread thread2 = new Thread(new ThreadStart(DoSomeWork));
            thread2.Name = "badegg";
            Thread.Sleep(1000);
            thread1.Start();
            Thread.Sleep(1000);
            thread2.Start();
            Thread.Sleep(1000);
            ///執行緒0也只執行和其他執行緒相同的工作
            DoSomeWork();
        }

執行

   public static void Main(string[] args)
        {
            CountMutilThread cmt = new CountMutilThread();
            cmt.StartMain();
            Console.ReadLine();
        }

結果:

單例模式:確保單件有且僅有一個例項(不讓繼承,不讓構造等手段),並且提供一個對例項的訪問點。

單例的另外好辦法

 public class Dad
    {
        ///儲存唯一的例項 
        static Dad dad = new Dad();

        //為啦不讓例項化
        private Dad()
        {
          
        }
        
        //老爸只有一個,不能被多次建立,叫一下老爸,老爸就會出現
        public static  Dad sayDad()
        {
            return dad;
        }

        object ss = new object();
        ///故事內容
        private string content = "";
        ///講故事 
        public void tell()
        {
            lock (ss)
            {

                if (Thread.CurrentThread.Name == "mama")
                {
                    content = "老婆那畫面太美,我不敢想!";
                }
                else if (Thread.CurrentThread.Name == "me")
                {
                    content = "兒子,你小時候最乖啦,我們都很愛你。";
                }
                else
                {
                    content = "除來老婆和孩子,別人休想讓我講故事!";
                }
            }
        }

        ///獲得故事內容
        public string GetCounter()
        {
            return content;
        }
    }
View Code

 歡迎加入左上方群,交流探討c#設計模式

相關文章