【转】设计模式-观察者模式 设计模式-观察者模式

设计模式-观察者模式

定义

观察者模式(有时又被称为发布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或 从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理全部相依于它的观察者物件,而且在它自己的状态改变时主动发出通知。这一般透过呼叫各 观察者所提供的方法来实现。此种模式一般被用来实现事件处理系统。 html

基本简介

观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面能够做为一个观察者,业务 数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每一个类将重点放在某一个功能上,而不 是其余方面。一个对象只作一件事情,而且将他作好。观察者模式在模块之间划定了清晰的界限,提升了应用程序的可维护性和重用性。
观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,全部依赖于它的对象都获得通知并自动刷新。
 

(1)抽象主题(Subject)web

 持有一个观察者对象的集合,提供增长,删除观察者对象的接口,当须要关注的状态变化时候,须要通知全部持有的观察者对象。设计模式

(2)具体主题(Concrete Subject数组

 被观察者的具体实现...ide

(3)抽象观察者(Observerpost

 定义一个接口,在接受通知时候更新状态this

(4)具体观察者Concrete Observerurl

 观察者的具体实现...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)运行结果

 

优缺点

优势:
一、 Subject和Observer之间是松耦合的,分别能够各自独立改变。
二、 Subject在发送广播通知的时候,无须指定具体的Observer,Observer能够本身决定是否要订阅Subject的通知。
三、 遵照大部分GRASP原则和经常使用设计原则,高内聚、低耦合。
缺陷:
一、  依赖关系并未彻底解除,抽象通知者依旧依赖抽象的观察者。
二、 若是一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。
 
思考:抽象已经下降Subject和Observer之间的耦合度,可是他们之间依旧存在依赖。而咱们观察者模式一 定程度上注重着对观察者的通知,也就是动做的传递,目前Subject中依靠维持抽象具体观察对象,在发送通知时候循环每一个具体观察者,调用通知方法,那 么最终咱们的目的就是主题能调用相应的通知方法。换个角度说咱们是否是能够维护一个方法列表,那么C#中的委托(多播委托)彷佛能够实现咱们的这一目标。

 

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