观察者模式
首先,在这里我想说的是我写这篇文章的初衷。我是一篇面试题目的文章中看到这样一个问题:
猫大叫一声,所有的老鼠都开始逃跑,主人被惊醒。(C#语言)
要求: 1.要有联动性,老鼠和主人的行为是被动的。2.考虑可扩展性,猫的叫声可能引起其他联动效应。
那么,我们接下来就是针对这个问题,来谈谈我的想法。根据分析,我可以确定的是这个问题的解决方案可以用设计模式中的观察者模式。何谓是观察者模式?GOF对它进行了抽象,简称Observer模式,它定义了对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象被自动更新,是一种松耦合的设计模式。
Observer设计模式包含两类对象:
- Subject:监视对象,它往往包含着其他对象所感兴趣的内容。拿题目中来说,猫就是监视对象,它包含其他对象所感兴趣的内容,就是猫大叫一声,方法Cry()。
- Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在题目中,Observer有老鼠和主人,它们采取的行动分别是逃跑和惊醒。
代码如下:
1 /// <summary> 2 /// 观察者的行为 3 /// </summary> 4 public interface IObserver 5 { 6 //观察者的响应 7 void Response(); 8 } 9 10 /// <summary> 11 /// 监视对象的行为 12 /// </summary> 13 public interface ISubject 14 { 15 /// <summary> 16 /// 针对那些观察者,这里指猫针对的是老鼠和它的主人 17 /// </summary> 18 void AimAt(IObserver observer); 19 } 20 21 22 /// <summary> 23 /// 老鼠 24 /// </summary> 25 public class Mouse : IObserver 26 { 27 private string _name; 28 29 public Mouse(string name,ISubject subject) 30 { 31 _name = name; 32 subject.AimAt(this); 33 } 34 35 public void Response() 36 { 37 Console.WriteLine(_name+"试图去逃跑!"); 38 } 39 } 40 41 /// <summary> 42 /// 主人 43 /// </summary> 44 public class Master : IObserver 45 { 46 public Master(ISubject subject) 47 { 48 subject.AimAt(this); 49 } 50 51 public void Response() 52 { 53 Console.WriteLine("主人惊醒!"); 54 } 55 } 56 57 /// <summary> 58 /// 猫 59 /// </summary> 60 public class Cat : ISubject 61 { 62 private ArrayList _observers; 63 /// <summary> 64 /// 初始化相关观察者信息 65 /// </summary> 66 public Cat() 67 { 68 _observers=new ArrayList(); 69 } 70 71 /// <summary> 72 /// 给观察者提供信息 73 /// </summary> 74 /// <param name="observer"></param> 75 public void AimAt(IObserver observer) 76 { 77 this._observers.Add(observer); 78 } 79 80 /// <summary> 81 /// 叫的方法 82 /// </summary> 83 public void Cry() 84 { 85 Console.WriteLine("猫大叫一声!"); 86 foreach (IObserver observer in _observers) 87 { 88 observer.Response(); 89 } 90 } 91 }
客户端代码:
1 Cat cat = new Cat(); 2 Mouse mouse1 = new Mouse("米老鼠", cat); 3 Mouse mouse2 = new Mouse("米老鼠的儿子", cat); 4 Master master = new Master(cat); 5 cat.Cry(); 6 Console.ReadKey();
运行结果:
其实也可以用委托来写,委托其实是一种的特殊的类,但是委托的声明方式和类却完全不同。委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。还有一点就是:使用委托可以将多个方法绑定到同一个委托变量,当调用此变量时(这里用“调用”这个词,是因为此变量代表一个方法),可以依次调用所有绑定的方法。
代码如下:
1 //声明一个委托,它定义了可以代表的方法的类型 2 public delegate void SubEventHandler(); 3 /// <summary> 4 /// 抽象类,监视对象 5 /// </summary> 6 public abstract class Subject 7 { 8 //定义一个事件,相当于对委托变量的封装 9 public event SubEventHandler SubEvent; 10 /// <summary> 11 /// 大叫一声 12 /// </summary> 13 protected void FireAway() 14 { 15 if (this.SubEvent != null) 16 this.SubEvent(); 17 } 18 } 19 public class Cat : Subject 20 { 21 public void Cry() 22 { 23 Console.WriteLine("猫大叫了!"); 24 this.FireAway(); 25 } 26 } 27 public abstract class Observer 28 { 29 public Observer(Subject sub) 30 { 31 //当发生这个事件时候,注册一个响应的方法。 32 sub.SubEvent += new SubEventHandler(Response); 33 } 34 public abstract void Response(); 35 } 36 public class Mouse : Observer 37 { 38 private string name; 39 public Mouse(string name, Subject sub) 40 : base(sub) 41 { 42 this.name = name; 43 } 44 public override void Response() 45 { 46 Console.WriteLine(name + "赶紧逃啊!"); 47 } 48 } 49 public class Master : Observer 50 { 51 public Master(Subject sub) : base(sub) { } 52 public override void Response() 53 { 54 Console.WriteLine("主人突然醒了,神马情况!"); 55 } 56 }
运行的结果跟上面运行的结果是一样的。
水平有限,欢迎指导!