观察者模式(有时又被称为发布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或 从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理全部相依于它的观察者物件,而且在它自己的状态改变时主动发出通知。这一般透过呼叫各 观察者所提供的方法来实现。此种模式一般被用来实现事件处理系统。 html
(1)抽象主题(Subject)web
持有一个观察者对象的集合,提供增长,删除观察者对象的接口,当须要关注的状态变化时候,须要通知全部持有的观察者对象。设计模式
(2)具体主题(Concrete Subject)数组
被观察者的具体实现...ide
(3)抽象观察者(Observer)post
定义一个接口,在接受通知时候更新状态this
(4)具体观察者(Concrete Observer)url
观察者的具体实现...spa
UML图设计
示例
(1.1)抽象主题类Subject
/// <summary> /// 抽象主题 /// </summary> public abstract class Subject { /// <summary> /// 全部观察者对象 /// </summary> private List<Observer> observers = new List<Observer>(); /// <summary> /// 增长观察者对象 /// </summary> /// <param name="observer"></param> public void AddObserver(Observer observer) { observers.Add(observer); } /// <summary> /// 移除观察者对象 /// </summary> /// <param name="observer"></param> public void RemoveObserver(Observer observer) { observers.Remove(observer); } /// <summary> /// 发送通知 /// </summary> public void Notify() { foreach (var ob in observers) { ob.Update(); } } }
(1.2)具体主题类ConcreteSubject
/// <summary> /// 具体通知者 /// </summary> public class ConcreteSubject : Subject { /// <summary> /// 具体观察者状态 /// </summary> public string SubjectState { get; set; } }
(1.3)抽象观察者类
/// <summary> /// 观察者类 /// </summary> public abstract class Observer { public abstract void Update(); }
(1.4)具体观察者类
/// <summary> /// 具体观察者 /// </summary> public class ConcreteObserver : Observer { public string observerState { get; set; } public string Name { get; set; } public ConcreteSubject subjcSubject { get; set; } public ConcreteObserver(ConcreteSubject subject, string name) { this.Name = name; this.subjcSubject = subject; } public override void Update() { observerState = subjcSubject.SubjectState; System.Console.WriteLine("the observer's state of {0} is {1}", Name, observerState); } }
(1.5)控制台调用
class Program { static void Main(string[] args) { ConcreteSubject subject = new ConcreteSubject(); subject.AddObserver(new ConcreteObserver(subject, "ObA")); subject.AddObserver(new ConcreteObserver(subject, "ObB")); subject.AddObserver(new ConcreteObserver(subject, "ObC")); subject.SubjectState = "Ready"; subject.Notify(); System.Console.ReadKey(); } }
(1.6)运行结果
优缺点
C#委托改版
咱们以一个主题通知发送消息的例子来演示
(1.1)抽象主题
/// <summary> /// 抽象主题 /// </summary> public interface ISubject { void Notify(); }
(1.2)声明委托和具体主题
/// <summary> /// 声明委托 /// </summary> public delegate void MsgEvent(); /// <summary> /// 具体主题 /// </summary> public class ConcreteSubject : ISubject { /// <summary> /// 定义委托事件 /// </summary> public event MsgEvent MsgAction; /// <summary> /// 执行通知 /// </summary> public void Notify() { if (MsgAction != null) MsgAction(); } }
(1.3)添加具体观察者 站内信,邮件,短信
/// <summary> /// 站内信 /// </summary> public class InsideLetterMsg { /// <summary> /// 发送站内信 /// </summary> public void SendInsideLetterMsg() { Console.WriteLine("发送站内信....."); } } /// <summary> /// 邮件 /// </summary> public class MailMsg { /// <summary> /// 发送邮件 /// </summary> public void SendMailMsg() { Console.WriteLine("发送邮件....."); } } /// <summary> /// 短信 /// </summary> public class SMSMsg { /// <summary> /// 发送短信 /// </summary> public void SendSMSMsg() { Console.WriteLine("发送短信....."); } }
(1.4)客户端调用
class Program { static void Main(string[] args) { ConcreteSubject subject = new ConcreteSubject(); //注册事件 subject.MsgAction += (new InsideLetterMsg()).SendInsideLetterMsg; //站内信 subject.MsgAction += (new MailMsg()).SendMailMsg; //邮件 subject.MsgAction += (new SMSMsg()).SendSMSMsg; //短信 //开始发送消息了 subject.Notify(); Console.ReadKey(); } }
(1.5)结果
这个例子咱们更多关注的是行为,主题对于观察者行为的执行和通知。咱们只须要在调用的时候将观察者的方法注册到主题中便可。省去了主题须要维护观察者对象,循环调用观察者对象方法的过程。顺带咱们也看一下咱们建立的委托具体是what?
委托看一看
(1.1)看图说话
(1.2)System.MulticastDelegate
_invocationList一般这个字段为null,当咱们构造一个委托链是,他能够引用一个委托数组,也就是说咱们给委托+=方法时候,实际是操做它.
咱们能够推断出当咱们调用委托方法时候,代码大体是这样的(下面代码不是可运行的代码,只是预估大概的逻辑,仅供观看),不知道在观察者这块顺带写了下委托是否是有点
跑偏,委托这里只是顺带提一下,更多的知识面确定没涉及到,只是帮助你们理解下.
//从委托链中获取 Delegate[] deleagetset = _invocationList as Delegate[]; if (deleagetset != null) { foreach (MsgAction m in deleagetset) { m(value); //调用每一个委托 } } else { //当前不是委托链 直接 invoke _methodPtr.Invoke(_target, value); }
上边的例子只是单纯的循环,中途有一个调用委托失败都没有健壮的处理,因此MulticastDelegate类提供了另外一个实例方法GetInvocationList,用于显示调用链中的每个委托,具体你们能够查阅相关资料。That's all!
文章代码连接:http://files.cnblogs.com/files/mongo/BlogObserver.zip