1. 概述

  有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

2. 解决的问题

  将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。

3. 模式中的角色

  3.1 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

  3.2 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

  3.3 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

  3.4 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。

4. 模式解读

  4.1 观察者模式的类图  

  

  4.2 观察者模式的代码

    /// <summary>/// 抽象主题类/// </summary>public abstract class Subject{private IList<Observer> observers = new List<Observer>();/// <summary>/// 增加观察者/// </summary>/// <param name="observer"></param>public void Attach(Observer observer){observers.Add(observer);}/// <summary>/// 移除观察者/// </summary>/// <param name="observer"></param>public void Detach(Observer observer){observers.Remove(observer);}/// <summary>/// 向观察者(们)发出通知/// </summary>public void Notify(){foreach (Observer o in observers){o.Update();}}}/// <summary>/// 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己/// </summary>public abstract class Observer{public abstract void Update();}/// <summary>/// 具体观察者或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。/// </summary>public class ConcreteSubject : Subject{private string subjectState;/// <summary>/// 具体观察者的状态/// </summary>public string SubjectState{get { return subjectState; }set { subjectState = value; }}}/// <summary>/// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调/// </summary>public class ConcreteObserver : Observer{private string observerState;private string name;private ConcreteSubject subject;/// <summary>/// 具体观察者用一个具体主题来实现/// </summary>public ConcreteSubject Subject{get { return subject; }set { subject = value; }}public ConcreteObserver(ConcreteSubject subject, string name){this.subject = subject;this.name = name;}/// <summary>/// 实现抽象观察者中的更新操作/// </summary>public override void Update(){observerState = subject.SubjectState;Console.WriteLine("The observer's state of {0} is {1}", name, observerState);}}

  4.3 客户端代码

    class Program{static void Main(string[] args){// 具体主题角色通常用具体自来来实现ConcreteSubject subject = new ConcreteSubject();subject.Attach(new ConcreteObserver(subject, "Observer A"));subject.Attach(new ConcreteObserver(subject, "Observer B"));subject.Attach(new ConcreteObserver(subject, "Observer C"));subject.SubjectState = "Ready";subject.Notify();Console.Read();}}

  运行结果

  

5. 模式总结

  5.1 优点

    5.1.1 观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。

  5.2 缺点

    5.2.1 依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。

  5.3 适用场景

    5.3.1 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。

    5.3.2 一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。

6. 模式引申,应用C#中的事件委托来彻底解除通知者和观察者之间的耦合。

   6.1 关于委托的定义:委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法有相同的行为。委托方法可以像其它任何方法一样,具有参数和返回值。委托可以看作是对函数(方法)的的抽象,是函数的“类”,委托的实例代表一个(或多个)具体的函数,它可以是多播的。

   6.2 关于事件:事件基于委托,为委托提供了一种发布/订阅机制。事件的订阅与取消与我们刚才讲的观察者模式中的订阅与取消类似,只是表现形式有所不同。在观察者模式中,订阅使用方法Attach()来进行;在事件的订阅中使用“+=”。类似地,取消订阅在观察者模式中用Dettach(),而事件的取消用“-=”。

7. 下面例子分别用观察者模式,事件机制来实现

  7.1 实例描述:客户支付了订单款项,这时财务需要开具发票,出纳需要记账,配送员需要配货。

  7.2 观察者模式的实现

    7.2.1 类图

    

    7.2.2 代码实现

    /// <summary>/// 抽象观察者/// </summary>public interface ISubject{void Notify();}/// <summary>/// 工作岗位,作为这里的观察者的抽象/// </summary>public abstract class JobStation{public abstract void Update();}/// <summary>/// 具体主题,这里是客户/// </summary>public class Customer : ISubject{private string customerState;private List<JobStation> observers = new List<JobStation>();/// <summary>/// 增加观察者/// </summary>/// <param name="observer"></param>public void Attach(JobStation observer){this.observers.Add(observer);}/// <summary>/// 移除观察者/// </summary>/// <param name="observer"></param>public void Detach(JobStation observer){this.observers.Remove(observer);}/// <summary>/// 客户状态/// </summary>public string CustomerState{get { return customerState; }set { customerState = value; }}public void Notify(){foreach (JobStation o in observers){o.Update();}}}/// <summary>/// 会计/// </summary>public class Accountant : JobStation{private string accountantState;private Customer customer;public Accountant(Customer customer){this.customer = customer;}/// <summary>/// 更新状态/// </summary>public override void Update(){if (customer.CustomerState == "已付款"){Console.WriteLine("我是会计,我来开具发票。");accountantState = "已开发票";}}}/// <summary>/// 出纳/// </summary>public class Cashier : JobStation{private string cashierState;private Customer customer;public Cashier(Customer customer){this.customer = customer;}public override void Update(){if (customer.CustomerState == "已付款"){Console.WriteLine("我是出纳员,我给登记入账。");cashierState = "已入账";}}}/// <summary>/// 配送员/// </summary>public class Dilliveryman : JobStation{private string dillivierymanState;private Customer customer;public Dilliveryman(Customer customer){this.customer = customer;}public override void Update(){if (customer.CustomerState == "已付款"){Console.WriteLine("我是配送员,我来发货。");dillivierymanState = "已发货";}}}

    7.2.3 客户端代码

    class Program{static void Main(string[] args){Customer subject = new Customer();subject.Attach(new Accountant(subject));subject.Attach(new Cashier(subject));subject.Attach(new Dilliveryman(subject));subject.CustomerState = "已付款";subject.Notify();Console.Read();}}

    运行结果:

    我是会计,我来开具发票。
    我是出纳员,我给登记入账。
    我是配送员,我来发货。

  7.3 事件实现

    7.3.1 类图

    

    通过类图来看,观察者和主题之间已经不存在任何依赖关系了。

    7.3.2 代码实现

    

    /// <summary>/// 抽象主题/// </summary>public interface ISubject{void Notify();}/// <summary>/// 声明委托/// </summary>public delegate void CustomerEventHandler();/// <summary>/// 具体主题/// </summary>public class Customer : ISubject{private string customerState;// 声明一个委托事件,类型为 CustomerEventHandlerpublic event CustomerEventHandler Update;public void Notify(){if (Update != null){// 使用事件来通知给订阅者Update();}}public string CustomerState{get { return customerState; }set { customerState = value; }}}/// <summary>/// 财务,已经不需要实现抽象的观察者类,并且不用引用具体的主题/// </summary>public class Accountant{private string accountantState;public Accountant(){ }/// <summary>/// 开发票/// </summary>public void GiveInvoice(){Console.WriteLine("我是会计,我来开具发票。");accountantState = "已开发票";}}/// <summary>/// 出纳,已经不需要实现抽象的观察者类,并且不用引用具体的主题/// </summary>public class Cashier{private string cashierState;public void Recoded(){Console.WriteLine("我是出纳员,我给登记入账。");cashierState = "已入账";}}/// <summary>/// 配送员,已经不需要实现抽象的观察者类,并且不用引用具体的主题/// </summary>public class Dilliveryman{private string dillivierymanState;public void Dilliver(){Console.WriteLine("我是配送员,我来发货。");dillivierymanState = "已发货";}}

    7.3.3 客户端代码

    class Program{static void Main(string[] args){Customer subject = new Customer();Accountant accountant = new Accountant();Cashier cashier = new Cashier();Dilliveryman dilliveryman = new Dilliveryman();// 注册事件subject.Update += accountant.GiveInvoice;subject.Update += cashier.Recoded;subject.Update += dilliveryman.Dilliver;/** 以上写法也可以用下面代码来替换subject.Update += new CustomerEventHandler(accountant.GiveInvoice);subject.Update += new CustomerEventHandler(cashier.Recoded);subject.Update += new CustomerEventHandler(dilliveryman.Dilliver);*/subject.CustomerState = "已付款";subject.Notify();Console.Read();}}

    运行结果

    我是会计,我来开具发票。
    我是出纳员,我给登记入账。
    我是配送员,我来发货。

转载于:https://www.cnblogs.com/Free-Thinker/p/4730227.html

设计模式学习笔记-观察者模式相关推荐

  1. 设计模式学习笔记-观察者模式(转)

    http://www.cnblogs.com/wangjq/archive/2012/07/12/2587966.html 1. 概述 有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系, ...

  2. Java-马士兵设计模式学习笔记-观察者模式-读取properties文件改成单例模式

    一.概述 1.目标:读取properties文件改成单例模式 二.代码 1.Test.java 1 class WakenUpEvent{ 2 3 private long time; 4 priva ...

  3. 7 种 Javascript 常用设计模式学习笔记

    7 种 Javascript 常用设计模式学习笔记 由于 JS 或者前端的场景限制,并不是 23 种设计模式都常用. 有的是没有使用场景,有的模式使用场景非常少,所以只是列举 7 个常见的模式 本文的 ...

  4. 设计模式学习笔记清单

    设计模式学习笔记清单 关于设计模式许多人已经耳熟能详,这段时间结合李建忠的教学视频以及大量网络资料,把这部分过了一遍,整理出学习笔记,而真正的深入学习和理解只能在具体的开发环境中日积月累.      ...

  5. 步步为营 .NET 设计模式学习笔记系列总结

    设计模式我从开篇到23种设计模式的讲解总共花了进两个月的时间,其间有很多读者给我提出了很好的建议,同时也指出了我的不足,对此我表示感谢,正是由于很多读者的支持我才能坚持的写到最后.在此表示我真诚的谢意 ...

  6. 设计模式学习笔记——观察者(Observer)模式

    设计模式学习笔记--观察者(Observer)模式 @(设计模式)[设计模式, 观察者模式, Observer] 设计模式学习笔记观察者Observer模式 基本介绍 观察者案例 类图 实现代码 Ob ...

  7. 设计模式学习笔记(目录篇)

    设计模式学习笔记(目录篇) 为了方便查看,特此将设计模式学习笔记系列单独做一个目录. 1   设计模式学习笔记(一:命令模式) 2   设计模式学习笔记(二:观察者模式) 3   设计模式学习笔记(三 ...

  8. 36设计模式学习笔记

    设计模式学习笔记 文章目录 0.设计模式简介 1.单例模式 2.工厂方法 3.抽象工厂 4.责任链模式 5.模板方法 ok 一.模板方法简介 二.模式的定义和特点 三.模式的结构和实现 四.什么是模板 ...

  9. 步步为营 .NET 设计模式学习笔记 一、开篇(设计模式之泡妞二十三招)

    园子里讲设计模式的太多了,最近我也在学设计模式,把我自己练的一些代码整理下,写个.NET设计模式学习笔记来让自己在设计模式的功底更深一层. 记得金庸小说里风清扬教令狐冲的时候,说过独孤九剑的总纲,无招 ...

最新文章

  1. **汇总CodeIgniter(CI)的数据库操作函数
  2. 关于64位 MS SQL 导入导出 Oracle 引发 ORA-06413 的解决方法
  3. 区块链100讲:区块链中的随机数
  4. js Date.parse()兼容性问题
  5. 红外热成像拥抱无人机 迸发安防救援新活力
  6. 那些年,使用Github的正确姿势
  7. mnist等常用数据集下载地址,现成的.mat文件
  8. C++ map基本操作
  9. 从Ubuntu命令行按进程名称杀死进程
  10. ArcGIS Engine开发之旅02--ArcGIS Engine中的类库
  11. php 获取 js json数据类型,JS基础-JS的数据类型和访问/流程控制/JSON格式字符串和js对象相互转换...
  12. 关于ios在H5页面长按识别二维码无效
  13. 网络IO之阻塞、非阻塞、同步、异步总结
  14. 【API进阶之路】用API打造一条自动化内容生产流水线
  15. Go语言基础进阶—程序结构—声明
  16. axure 抖音部件库_原型技巧:如何用Axure画出抖音APP页面色彩风格(干货技能)...
  17. kindle导出电子书pc_使用Kindle for PC预览和购买电子书
  18. 谷歌大脑组合模型霸榜 SuperGLUE,什么模型这么高?
  19. 关于IDEA下载安装,jpcap与wincap的一些使用方法
  20. Re5:读论文 TWAG: A Topic-guided Wikipedia Abstract Generator

热门文章

  1. cin、cin.get()、cin.getline()、getline()、gets()等函数的用法(转)
  2. vscode --- 快捷键格式化代码时,分号消失
  3. javascript --- 抽象相等
  4. LAMP(7限定某个目录禁止解析php、 限制user_agent、 PHP相关配置、PHP扩展模块
  5. Windows系统下oracle数据库每天定时备份
  6. iOS开发CoreAnimation解读之三——几种常用Layer的使用解析
  7. 为MFC中的ListBox添加水平滚动条
  8. 主域控宕机无法恢复后,如何配置辅助域控继续工作
  9. 关于Linux下的umask
  10. 2010年06月12日