定义
观察者模式(有时又被称为发布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
基本简介
(1)抽象主题(Subject)
持有一个观察者对象的集合,提供增加,删除观察者对象的接口,当需要关注的状态变化时候,需要通知所有持有的观察者对象。
(2)具体主题(Concrete Subject)
被观察者的具体实现...
(3)抽象观察者(Observer)
定义一个接口,在接受通知时候更新状态
(4)具体观察者(Concrete Observer)
观察者的具体实现...
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