序言
點選檢視:設計模式系列
咳咳,今天起,我要把對設計模式的理解心得,用全新的案例去分析,分享給大家。希望大家能夠喜歡。
觀察者模式
舉例闡述:遊戲情節,一顆小男孩,丟到眾多鬼子附近,爆炸啦,根據炸彈的威力計算爆炸後鬼子的血量,假定有些鬼子有防具,有些鬼子沒有防具。
分析:這種情況,使用觀察者模式是比較理想的,因為觀察者模式的就是是處理物件間一對多的依賴關係的,當一個物件發生變化,其它依賴他的物件都要得到通知並更新。
定義:在觀察者模式中,上述小男孩被稱為主題,而小鬼子們就被稱為觀察者。
下面我用程式碼,把舉例給演示出來。
定義觀察者模式中的主題。
//炸彈 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; } }