转载:http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx

假设我们有个高档的热水器,我们给它通上电,当水温超过95度的时候:1、扬声器会开始发出语音,告诉你水的温度;2、液晶屏也会改变水温的显示,来提示水已经快烧开了。

现在假设热水器由三部分组成:热水器、警报器、显示器,它们来自于不同厂商并进行了组装。那么,应该是热水器仅仅负责烧水,它不能发出警报也不能显示水温;在水烧开时由警报器发出警报、显示器显示提示和水温。

代码如下:

// 热水器
public class Heater {
private int temperature; // 烧水
private void BoilWater() {
for (int i = ; i <= ; i++) {
temperature = i;
}
}
} // 警报器
public class Alarm{
private void MakeAlert(int param) {
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param);
}
} // 显示器
public class Display{
private void ShowMsg(int param) {
Console.WriteLine("Display:水已烧开,当前温度:{0}度。" , param);
}
}

这里就出现了一个问题:如何在水烧开的时候通知报警器和显示器?在继续进行之前,我们先了解一下Observer设计模式,Observer设计模式中主要包括如下两类对象:

  1. Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
  2. Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。

在本例中,事情发生的顺序应该是这样的:

  1. 警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
  2. 热水器知道后保留对警报器和显示器的引用。
  3. 热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。

类似这样的例子是很多的,GOF对它进行了抽象,称为Observer设计模式:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。

代码如下:

using System;
using System.Collections.Generic;
using System.Text; namespace Delegate {
// 热水器
public class Heater {
private int temperature;
public delegate void BoilHandler(int param); //声明委托
public event BoilHandler BoilEvent; //声明事件 // 烧水
public void BoilWater() {
for (int i = ; i <= ; i++) {
temperature = i; if (temperature > ) {
if (BoilEvent != null) { //如果有对象注册
BoilEvent(temperature); //调用所有注册对象的方法
}
}
}
}
} // 警报器
public class Alarm {
public void MakeAlert(int param) {
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
} // 显示器
public class Display {
public static void ShowMsg(int param) { //静态方法
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
}
} class Program {
static void Main() {
Heater heater = new Heater();
Alarm alarm = new Alarm(); heater.BoilEvent += alarm.MakeAlert; //注册方法
heater.BoilEvent += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.BoilEvent += Display.ShowMsg; //注册静态方法 heater.BoilWater(); //烧水,会自动调用注册过对象的方法
}
}
}
输出为:
Alarm:嘀嘀嘀,水已经 度了:
Alarm:嘀嘀嘀,水已经 度了:
Display:水快烧开了,当前温度:96度。
// 省略...

观察者(observer)设计模式的更多相关文章

  1. C#委托与事件之观察者Observer设计模式

    前言    委托: 委托是一种在对象里保存方法引用的类型,同时也是一种类型安全的函数指针. 或委托可以看成一种表示函数的数据类型,类似函数指针. 事件是特殊的委托 观察者模式:两种角色:(1)Subj ...

  2. 设计模式 策略-Strategy,装饰-Decorator,观察者-Observer

    重温了Head First 3个设计模式.提炼一下思想,笔记如下. 策略-Strategy 当一个类或类族中重复实现某些同类的方法(behavior)时,考虑使用策略模式. 该模式是将Behavior ...

  3. 面向对象设计模式——观察者(OBSERVER)模式

    定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.  Observer模式描述了如何建立这种关系.这一模式中的关键对象是目标(subject ...

  4. 设计模式之观察者(OBSERVER)模式

    定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.  Observer模式描述了如何建立这种关系.这一模式中的关键对象是目标(subject ...

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

    GOF给出的定义: Define a one-to-many dependency between objects so that when one object changes state, all ...

  6. Java设计模式之从[星际争霸的兵种升级]分析观察者(Observer)模式

    观察者模式定义对象的一种一对多的依赖关系.当一个对象的状态发生改变时.全部依赖于它的对象都会得到通知并被自己主动更新. 一个简单的样例是.在星际争霸的虫族中有一个0基础单位叫做跳狗(Zergling) ...

  7. 设计模式C++描述----04.观察者(Observer)模式

    一. 概述 Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变. Sbuject 相当于 ...

  8. 利用 SPL 快速实现 Observer 设计模式

    目录: 1.什么是 SPL 2.SplSubject 和 SplObserver 接口 3.为什么使用 SplObjectStorage 类 4.模拟案例 5.结束语 6.下载资源 什么是 SPL S ...

  9. Observer设计模式中-委托事件-应用在消息在窗体上显示

    Observer设计模式:监视者模式.在类中的方法中处理的结果或者消息通过事件委托 的方式发送给主窗体. 因为在其它类中直接访问主窗体类,显示内容是不能直接调用控件赋值的,当然也有别的类似查阅控件名, ...

  10. 转载:C#中委托、事件与Observer设计模式

    原文地址 http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx 感谢博主分享! 范例说明 假设 ...

随机推荐

  1. linux内核设计与实现--从内核出发

    linux内核有两种版本:稳定的和处于开发中的. linux通过一种简单的命名机制来区分稳定的和处于开发中的内核,使用3个或者4个“.”分割的数字来代表不同内核版本. 如:2.6.26.1:第一个数字 ...

  2. maven项目导入eclipse

    maven项目的配置文件 web java文件都在src下面 src/main/java src/main/webapp src/main/webapp/web-inf 导入后要重新添加jar包,设置 ...

  3. golang 移动应用例子 example/basic 源码框架分析

    条件编译 我们在源码中可以看到2个文件: main.go 和 main_x.go 这两个包名都是 package main , 都有 main 函数. 不会冲突么? 答案是不会的, main_x.go ...

  4. linux驱动学习之Input输入子系统

    以前,看过国嵌关于input子系统的视频课程,说实话,我看完后脑子里很乱,给我的印象好像是input子系统驱动是一个全新的驱动架构,疑惑相当多.前几天在网上,看到有很多人介绍韦东山老师的linux驱动 ...

  5. MSSQL中的随机函数

    随机函数:rand()在查询分析器中执行:select rand(),可以看到结果会是类似于这样的随机小数:0.36361513486289558,像这样的小数在实际应用中用得不多,一般要取随机数都会 ...

  6. iframe 跨域自适应 纯css解决方法

    <style type="text/css">body{background:#f00;}body, html,#ifm1{width:100%;height:100% ...

  7. (easy)LeetCode 219.Contains Duplicate II

    Given an array of integers and an integer k, find out whether there there are two distinct indices i ...

  8. java7新特性 java8新特性

    Java 7 的7个新特性 Java7语法新特性 JAVA8 十大新特性详解 http://www.jb51.net/article/48304.htm

  9. Spring Data Jpa真爽啊

    http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-jpa/ 持久层的实现类可以让框架生成.只需要声明持久层接口,框架直接生成代理 ...

  10. SparseArray,dip & px

    SparseArray-用Array的方式实现Integer-Object的map 优:节约内存,因为避免了装箱/拆箱,数据结构不依赖Entry 劣:速度不及HashMap dip.px dip(de ...