首页 > 代码库 > 设计模式-单例模式,观察者模式
设计模式-单例模式,观察者模式
序言
咳咳,今天起,我要把对设计模式的理解心得,用全新的案例去分析,分享给大家。希望大家能够喜欢。
观察者模式
举例阐述:游戏情节,一颗小男孩,丢到众多鬼子附近,爆炸啦,根据炸弹的威力计算爆炸后鬼子的血量,假定有些鬼子有防具,有些鬼子没有防具。
分析:这种情况,使用观察者模式是比较理想的,因为观察者模式的就是是处理对象间一对多的依赖关系的,当一个对象发生变化,其它依赖他的对象都要得到通知并更新。
定义:在观察者模式中,上述小男孩被称为主题,而小鬼子们就被称为观察者。
下面我用代码,把举例给演示出来。
定义观察者模式中的主题。
//炸弹 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; } }