观察者模式是经常使用到的一种设计模式,在我们的生活中也经常遇到,小到学校上学让同学帮忙看着老师有没有过来,在教室里做一些与学习无关的事情,大到股市里面我们遇到的,到股票涨到或者跌到一定程度的时候通知我们,卖出或者买入一定的股份,貌似观察者模式是经常使用到的一种设计模式。
下面我就用生活中的一个实例来简单的说明观察者模式怎么使用。
小明有一天发现自己原有的手机卡资费有点贵,准备换一张资费便宜的手机卡,换手机卡好麻烦,首先应该解决的问题就是一定要通知他之前的一个班级同学,把新的手机号告诉他们,以便有事情的时候能够经常的联系,好了这个该怎么设计呢?
首先,我们先进行分析一下这个设计的方法,小明如果要是通知自己的班级同学,首先应该是采用批量通知的方式,一个一个的通知是不是很不便利了,既然是批量通知,我们应该在通知者类中添加所有的要通知的同班同学(观察者),然后实现遍历通知,既然要使用遍历通知,那么一定要保证每个同学里面包含的通知方法应该是一样的,这样就需要抽象出来一个同学基类,这样子的分析以后就应该很清楚了,但是一定要弄明白的是,这些通知最终调用的还是同学(观察者)自身的方法,那么,作为通知者,通知的内容怎么传递过去,最简单的办法就是在其基类的构造函数中进行传递。好了,分析结束,那么我们具体应该建立哪些类呢,首先应该建立一个通知者基类、具体的通知者,另外观察者呢?也应该建立相应的观察者基类,具体的观察者。
首先,我们来看一下具体的UML图:
上图就是整个观察者模式的一个UML简图,那么,具体类的实现我们怎么实现呢?代码如下
namespace Observer{ public interface Subject { void Add(Observer observer); void Remove(Observer observer); void Notify(); string SubjectState { set; get; } }}
namespace Observer{ public class XiaoMing : Subject { private string changeCard; private ListList = new List (); public void Add(Observer observer) { List.Add(observer); } public void Remove(Observer observer) { List.Remove(observer); } public void Notify() { foreach (Observer observer in List) { observer.Update(); } } public string SubjectState { get { return changeCard; } set { changeCard = value; } } }}
namespace Observer{ public abstract class Observer { protected string name; protected Subject sub; public Observer(string name, Subject sub) { this.name = name; this.sub = sub; } public abstract void Update(); }}
namespace Observer{ public class BuilderContact : Observer { public BuilderContact(string name, Subject sub) : base(name, sub) { } public override void Update() { Console.WriteLine("{0},{1},伟大的社会建设者,麻烦您记一下!", this.sub.SubjectState, this.name); } }}
namespace Observer{ public class TeacherContact : Observer { public TeacherContact(string name, Subject sub) : base(name, sub) { } public override void Update() { Console.WriteLine("{0},{1},伟大的人民教师,麻烦您记一下!", this.sub.SubjectState, this.name); } }}
namespace Observer{ class Program { static void Main(string[] args) { XiaoMing xiaoMing = new XiaoMing() { SubjectState = "我手机号换了" }; BuilderContact builder = new BuilderContact("李四", xiaoMing); TeacherContact teacher = new TeacherContact("小红", xiaoMing); xiaoMing.Add(builder); xiaoMing.Add(teacher); xiaoMing.Notify(); Console.ReadKey(); } }}
以上是一个简单的观察者模式的实例,但是问题来了,不管是哪个观察者执行的都是Update方法,这样的设计显然影响了程序的可读性,但是我们怎样才能是程序的可读性更强呢?又或者当小明刚办好这个手机卡,糟糕的事情发生了,欢喜之下,手机卡丢了,手机也丢了,联系方式全都没有呢,悲剧又一次在小明的身上发生了,怎么才能获取所有同学的联系方式呢,还好聪明的小明记得其中一个同学的号码,然他通知所有的同学,让同学给他发联系方式,这种方法真的是太棒了,那具体到我们的代码又该怎样的实现呢?
具体的代码实现如下:
namespace DelegateObserver{ public interface Subject { void Notify(); string SubjectState { set; get; } }}
namespace DelegateObserver{ public delegate void Update(); public class XiaoMing : Subject { public Update Update; private string losePhone; public void Notify() { Update(); } public string SubjectState { get { return losePhone; } set { losePhone = value; } } }}
namespace DelegateObserver{ public class BuilderContact { private string name; private Subject sub; public BuilderContact(string name, Subject sub) { this.name = name; this.sub = sub; } public void StopBuilder() { Console.WriteLine("{0},{1},伟大的社会建设者,请你给他发一个信息!", this.sub.SubjectState, this.name); } }}
namespace DelegateObserver{ public class TeacherContact { private string name; private Subject sub; public TeacherContact(string name, Subject sub) { this.name = name; this.sub = sub; } public void StopTeach() { Console.WriteLine("{0},{1},伟大的人民教师,请你给他发一个信息!", this.sub.SubjectState, this.name); } }}
namespace DelegateObserver{ public class XiaoWang { private XiaoMing xiaoMing; public XiaoWang(string subjectState) { xiaoMing = new XiaoMing { SubjectState = subjectState }; TeacherContact teacher = new TeacherContact("小红", xiaoMing); BuilderContact builder = new BuilderContact("李四", xiaoMing); xiaoMing.Update += new Update(teacher.StopTeach); xiaoMing.Update += new Update(builder.StopBuilder); } public void Nofity() { xiaoMing.Notify(); } }}
namespace DelegateObserver{ class Program { static void Main(string[] args) { XiaoWang xiaoWang = new XiaoWang("小明手机丢了"); xiaoWang.Nofity(); Console.ReadKey(); } }}
好了,以上通过委托进行了解耦,同时可读性也增强了,在此证明了一点,在实际的使用过程中带有委托的观察者模式更加强大,总归,观察者模式的运用场景就是在一个类的改变影响到其他的类的时候使用。
本篇文章观察者模式至此,谢谢您收看我的博客。