一、定义

观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

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

观察者模式是写松耦合代码的必备模式。

二、结构

三、实现

//被观察者

public interface IObject
{ IList<IMonitor> ListMonitor { get; set; } //定义观察者集合,因为多个观察者观察一个对象,所以这里用集合
string SubjectState { get; set; } //被观察者的状态 void AddMonitor(IMonitor monitor); //添加一个观察者 void RemoveMonitor(IMonitor monitor); //移除一个观察者 void SendMessage(); //向所有观察者发送消息 }
public class Subject : IObject
{ private IList<IMonitor> listMonitor = new List<IMonitor>(); public string SubjectState //被观察者的状态
{
get;set;
} public IList<IMonitor> ListMonitor //实现具体的观察者列表属性
{
get { return listMonitor; }
set { listMonitor = value; }
} public void AddMonitor(IMonitor monitor) //实现具体的添加观察者方法
{
listMonitor.Add(monitor); } public void RemoveMonitor(IMonitor monitor) //实现具体的移除观察者方法
{ listMonitor.Remove(monitor);
} public void SendMessage() //实现具体的发送消息方法
{
foreach (IMonitor m in listMonitor) //发送给所有添加过的观察者,让观察者执行update方法以同步更新自身状态
{
m.Update();
}
}
} //观察者 public interface IMonitor //定义观察者接口
{
void Update();
} public class Monitor : IMonitor //实现具体观察者
{
private string monitorState="Stop!"; //观察者初始状态,会随着被观察者变化而变化
private string name; //观察者名称,用于标记不同观察者
private IObject subject; //被观察者对象 public Monitor (IObject subject, string name) //在构造观察者时,传入被观察者对象,以及标识该观察者名称
{
this.subject = subject;
this.name = name;
Console.WriteLine("我是观察者{0},我的初始状态是{1}", name, monitorState); } public void Update() //当被观察者状态改变,观察者需要随之改变
{
monitorState = subject.SubjectState;
Console.WriteLine("我是观察者{0},我的状态是{1}", name, monitorState); }
} //前端调用 static void Main(string[] args)
{ IObject subject = new Subject();
subject.AddMonitor(new Monitor(subject, "Monitor_1"));
subject.AddMonitor(new Monitor(subject, "Monitor_2"));
subject.AddMonitor(new Monitor(subject, "Monitor_3")); subject.SubjectState = "Start!";
subject.SendMessage(); Console.Read();
}
}

四、适用场景

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

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

五、优缺点

  优点

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

  缺点

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

六、模式引申

  应用C#中的事件委托来彻底解除通知者和观察者之间的耦合。

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

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

七、答疑

1. 在普通的观察者模式中,解耦并不彻底,那么在事件的发布订阅模型中,解耦彻底吗?为什么?

答案是肯定的。因为在事件中,订阅者和发布者之间是通过把事件处理程序绑定到委托,并不是把自身传给对方。所以解决了观察者模式中不完全解耦的问题。这也是关键点之四

2. 通过委托绑定方法来实现观察者模式,会不会有什么隐患?

有的,通过+=去把方法绑定到委托,很容易忘记-=。如果只绑定不移除,这个方法会一直被引用。我们知道GC去回收的时候,只会处理没有被引用的对象,只要是还被引用的对象时不会被回收掉的。所以如果在长期不关闭的系统中(比如监控系统),大量的代码使用+=而不-=,运行时间长以后有可能会内存溢出。

3. 事件,委托,观察者模式之间的关系

这个上面已经提到了,委托时一种类型,事件是一种特殊的委托,观察者模式是一种设计模式,事件的机制是观察者模式的一种实现,其中订阅者和发布者通过委托实现协同工作。

好的,最后我们还是来归纳一下观察者模式的关键点

一、每个观察者需要被保存到被观察者的集合中,并且被观察者提供添加和删除的方式。

二、被观察者把自己传给观察者,当状态改变后,通过遍历或循环的方式逐个通知列表中的观察者。

三、虽然解耦了观察者和被观察者的依赖,让各自的变化不大影响另一方的变化,但是这种解耦并不是很彻底,没有完全解除两者之间的耦合。

四、在事件中,订阅者和发布者之间是通过把事件处理程序绑定到委托,并不是把自身传给对方。所以解决了观察者模式中不完全解耦的问题

注意点:在使用委托绑定方法时,需要注意移除方法,否则可能会造成内存溢出。

建议:不能理解事件和委托的同学,好好地把事件和委托看一看,并且自己写点代码加深印象。

参考:

http://blog.jobbole.com/109845/

http://www.cnblogs.com/wangjq/archive/2012/07/12/2587966.html

欢迎阅读本系列文章:Head First设计模式之目录

Head First设计模式之观察者模式的更多相关文章

  1. 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)

    原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...

  2. 设计模式之观察者模式(Observable与Observer)

    设计模式之观察者模式(Observable与Observer) 好久没有写博客啦,之前看完了<设计模式之禅>也没有总结一下,现在回忆一下设计模式之观察者模式. 1.什么是观察者模式 简单情 ...

  3. 8.5 GOF设计模式四: 观察者模式Observer

    GOF设计模式四: 观察者模式Observer  现实中遇到的问题  当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式  观察者模式 ...

  4. php 设计模式之观察者模式(订阅者模式)

    php 设计模式之观察者模式 实例 没用设计模式的代码,这样的代码要是把最上面那部分也要符合要求加进来,就要修改代码,不符合宁增不改的原则 介绍 观察者模式定义对象的一对多依赖,这样一来,当一个对象改 ...

  5. [JS设计模式]:观察者模式(即发布-订阅者模式)(4)

    简介 观察者模式又叫发布---订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 举一个现实生活中的例子,例如小 ...

  6. 实践GoF的23种设计模式:观察者模式

    摘要:当你需要监听某个状态的变更,且在状态变更时通知到监听者,用观察者模式吧. 本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:观察者模式>,作者: 元闰子 . 简介 现在有 ...

  7. java设计模式之观察者模式

    观察者模式 观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式)是软件设计模式的一种.在此种模 ...

  8. [python实现设计模式]-4.观察者模式-吃食啦!

    观察者模式是一个非常重要的设计模式. 我们先从一个故事引入. 工作日的每天5点左右,大燕同学都会给大家订饭. 然后7点左右,饭来了. 于是燕哥大吼一声,“饭来啦!”,5点钟定过饭的同学就会纷纷涌入餐厅 ...

  9. 【GOF23设计模式】观察者模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_观察者模式.广播机制.消息订阅.网络游戏对战原理 package com.test.observer; import ja ...

  10. 设计模式学习——观察者模式(Observer Pattern)

    0. 前言 观察者模式在许多地方都能够用到,特别是作为MVC模式的一部分,在MVC中,模型(M):存放数据,视图(V):显示数据.当模型中的数据发生改变时,视图会得到通知,这是典型的观察者模式. 1. ...

随机推荐

  1. CentOS7操作系统参数优化

    生产环境配置需要标准化,将常用操作写成脚本用于操作系统的初始化. #!/bin/bash #Date:2017 #This Script is for centos7.3 init #01.配置yum ...

  2. java 之 单例模式(大话设计模式)

    笔者记得去面试时曾被问起这个模式,当时还没有看过设计模式,对设计模式基本上一无所知,不过可以肯定的是笔者用过单例模式.当时回答的风马牛不相及,很尴尬. 也是从那时起,开始学习设计模式.今天所说的就是单 ...

  3. 这个接口管理平台 eoLinker 开源版部署指南你一定不想错过

    本文主要内容是讲解如何在本地部署eoLinker开源版. 环境要求 1.PHP 5.5+ / PHP7+(推荐) 2.Mysql 5.5+ / Mariadb 5.5+ 3.Nginx(推荐) / A ...

  4. Jarvis OJ - [XMAN]level1 - Writeup——简单shellcode利用

    100分的pwn 简单查看一下,果然还是比较简单的 放到ida中查看一下,有明显的溢出函数,并且在函数中打印出了字符串的地址,并且字符串比较长,没有NX保护 所以我们很容易想到构造shellcode, ...

  5. J2EE十三个规范小结

    J2ee是我们步入java学习的一个開始.它将开启这趟奇幻之旅,Java是一种简单的,跨平台的,面向对象的,分布式的.解释的.健壮的安全的.结构的中立的,可移植的.性能非常优异的多线程的,动态的语言. ...

  6. 知名互联网公司校招 Java 开发岗面试知识点解析

    天之道,损有余而补不足,是故虚胜实,不足胜有余. 本文作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向.在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几 ...

  7. 用IFeatureWorkspaceAnno.CreateAnnotationClass 创建注记图层时报“The application is not licensed to modify or create schema”的错误的解决方案。

    用IFeatureWorkspaceAnno.CreateAnnotationClass 的方法创建注记图层的时候报"The application is not licensed to m ...

  8. NodeJs学习笔记(四)---单元测试

         sailsjs框架用了一段时间了,感觉如果功能复杂了,非常难以处理,想用一下单元测试,看是否能解决问题.     sailsjs的官方文档使用的是mocha,我搜索了一些资料,主要参考了朴灵 ...

  9. Bootstrap学习笔记(二)---常见工具和流程导航范例

    使用bootstrap框架避免不了写CSS,当CSS文件较大时,会发现维护起来很麻烦,一些默认值,如行高.背景色.标注颜色.字号等信息往往反复出现,还有一些大体上一致,只有小部分不同的样式定义,这就需 ...

  10. SSH连接工具:SecureCRT设置,另一个SSH连接工具:Xshell。在Windows和Linux之间互传文件可用WinSCP

    一般Linux发行版不允许root远程登录,CentOS允许. 调整字体大小: