一、概述
在软件设计工作中会存在对象之间的依赖关系,当某一对象发生变化时,所有依赖它的对象都需要得到通知。如果设计的不好,很容易造成对象之间的耦合度太高,难以应对变化。使用观察者模式可以降低对象之间的依赖,以松耦合的方式实现这一目标。

二、观察者模式
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。其结构图如下:

Subject知道它的所有观察者并提供了观察者注册和删除订阅的接口。
Observer为那些在目标发生改变时需获得通知的对象定义一个更新接口。
ConcreteSubject实现Subject接口,当改变状态时向依赖于它的ConcreteObserver发送通知。
ConcreteObserver实现Observer的更新接口,使得自身能根据ConcreteSubject状态的不同而做出相应的改变。
观察者模式分为推模式和拉模式两种。推模式是当有通知时,把依赖对象的信息以参数的形式传递给所有观察者,而拉模式通知方法本身并不带任何的参数,是由观察者自己到依赖对象那里取回相关信息。在推模式下,所有观察者都通过参数传递的方式得到依赖对象的全部信息,与依赖对象之间的耦合较低,但不能实现“按需所取”所需要信息的。而拉模式仅仅是通知观察者,至于要不要提取依赖对象的信息则是观察者自己的事情,这么一来就实现“按需所取”,但往往要在ConcreteObserver里保存一个ConcreteSubject的引用,与ConcreteSubject的耦合也加强了。
观察者模式的Subject一般需要提供观察者注册和删除订阅的接口,但在.NET中,往往可以利用事件和委托的特性来实现观察者模式,这是一种更为优雅的方案。

三、示例
我们现在利用事件实现观察者模式。我们设计一个信用卡消费的简单例子,在消费的同时需要对用户账户进行扣款,同时对用户进行短信提醒。
首先定义信用卡类,当消费金额变动时会触发Notify方法通知该对象的所有观察者。

public class CreditCard : EventArgs
{
private float _spendAmount;
public event EventHandler<CreditCard> SpendMoney; public float SpendAmount
{
get
{
return _spendAmount;
}
set
{
_spendAmount = value;
Notify();
}
} private void Notify()
{
if (SpendMoney != null)
{
SpendMoney(this, this);
}
}
}

接着定义Observer接口,并使用户帐户类和短信提醒类实现这个接口,其中这两个ConcreteObserver类的Update方法签名必须与CreditCard中的事件SendMoney一致,否则就无法注册到CreditCard。

public interface IObserver<T>
{
void Update(Object sender, T e);
} public class SMSNotify : IObserver<CreditCard>
{
public void Update(Object sender, CreditCard e)
{
Console.WriteLine("Sms notify.Spend {0}", e.SpendAmount);
}
} public class Account : IObserver<CreditCard>
{
private float _accountAmount; public Account(float accountAmount)
{
_accountAmount = accountAmount;
} public void Update(Object sender, CreditCard e)
{
_accountAmount += e.SpendAmount;
Console.WriteLine("Account amount is {0}", _accountAmount);
}
}

最后看一下客户端调用。

static void Main(string[] args)
{
CreditCard creditCard = new CreditCard();
SMSNotify sms = new SMSNotify();
Account account = new Account();
creditCard.SpendMoney += account.Update;
creditCard.SpendMoney += sms.Update;
creditCard.SpendAmount = ;
}

观察者模式(Observer Pattern)的更多相关文章

  1. 设计模式 - 观察者模式(Observer Pattern) 详细说明

    观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...

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

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

  3. 设计模式 - 观察者模式(Observer Pattern) 详细解释

    观察者模式(Observer Pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...

  4. 设计模式-观察者模式(Observer Pattern)

    观察者模式(Observer Pattern):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己. 观察者 ...

  5. jQuery中的观察者模式(Observer Pattern)

    在jQuery中,on方法可以为元素绑定事件,trigger方法可以手动触发事件,围绕这2个方法,我们来体验jQuery中的观察者模式(Observer Pattern). ■ on方法绑定内置事件, ...

  6. 设计模式 - 观察者模式(Observer Pattern) Java内置 用法

    观察者模式(Observer Pattern) Java内置 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 ...

  7. 二十四种设计模式:观察者模式(Observer Pattern)

    观察者模式(Observer Pattern) 介绍定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新. 示例有一个Message实体类,某些对象 ...

  8. 使用C# (.NET Core) 实现观察者模式 (Observer Pattern) 并介绍 delegate 和 event

    观察者模式 这里面综合了几本书的资料. 需求 有这么个项目: 需求是这样的: 一个气象站, 有三个传感器(温度, 湿度, 气压), 有一个WeatherData对象, 它能从气象站获得这三个数据. 还 ...

  9. php观察者模式(observer pattern)

    ... <?php /* The observer pattern implements a one-too-many dependency between objects. The objec ...

  10. 设计模式系列之观察者模式(Observer Pattern)

    意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作 ...

随机推荐

  1. Spark记录-SparkSQL远程操作MySQL和ORACLE

    1.项目引入mysql和oracle驱动 2.将mysql和oracle驱动上传到hdfs 3.远程调试源代码如下: import org.apache.spark.sql.SQLContext im ...

  2. HTML5 元素拖拽实现 及 jquery.event.drag插件

    如上图片: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" c ...

  3. u-boot移植(一)---准备工作

    一.工具链的制作 1.1 工具 软件工具:crosstool-ng 下载地址:git clone https://github.com/crosstool-ng/crosstool-ng crosst ...

  4. 集大软件工程15级个人作业Week1

    集大软件工程15级个人作业Week1 孙志威 201521123077 博客园主页 码云地址 阅读参考材料,并回答下面几个问题 (1)回想一下你初入大学时对网络工程专业的畅想 当初你是如何做出选择网络 ...

  5. 20155209 2016-2017-2 《Java程序设计》第九周学习总结 ## 教材学习内容总结

    教材学习内容总结 JDBC API 允许用户访问任何形式的表格数据,尤其是存储在关系数据库中的数据. 执行流程: •连接数据源,如:数据库. •为数据库传递查询和更新指令. •处理数据库响应并返回的结 ...

  6. elasticsearch 单机多实例

    elasticsearch 配置单机器多实例 host: - - path data: /opt/elasticsearch/data/node1 /opt/elasticsearch/data/no ...

  7. luogu P1943 LocalMaxima_NOI导刊2009提高(1)

    又是有关于\(1-n\)排列的题,考虑从大到小依次插入构造排列 对于第\(i\)个数(也就是\(n-i+1\)),只有当它插在当前排列最前面时才会使那个什么数的个数+1,而在最前面的概率为\(\fra ...

  8. 创建Git独立分支

    在使用git进行版本控制的某些场景中我们可能需要在一个项目中建立完全独立的分支,此分支将作为一个独立的版本历史根节点,不与之前任何分支拥有相同的版本祖先. 比如当我们要在一个项目中使用一个分支进行项目 ...

  9. 关于形如--error LNK2005: xxx 已经在 msvcrtd.lib ( MSVCR90D.dll ) 中定义--的问题分析解决

    转自:http://hi.baidu.com/qinfengxiaoyue/item/ff262ccfb53b4c2ba0b50a89 引自:http://blog.csdn.net/sptoor/a ...

  10. WPF工具开发: 第三库选择

    PropertyGrid Winforms's PropertyGrid 非WPF原生支持, 需要借助WinFormHost 风格不可定制 PropertyInspectorView 算是" ...