原文链接
Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件 | Jason_c
原文写得很好,但是主题格式我不太喜欢,所以我对文章的格式进行了修整,方便自己日后阅读
正文
六、观察者模式
观察者模式:有时又被称为 发布(Publish )-订阅(Subscribe)模式 、模型-视图(View)模式、源-收听者(Listener)模式或 从属者模式;
观察者设计模式定义了对象间的一种 一对多 的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
实现观察者模式有很多形式,比较直观的一种是使用一种 “注册——通知——撤销注册” 的形式:
- 观察者(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
- 被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。
- 观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
实现观察者模式的时候要 注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来。无论是观察者 “观察” 观察对象,还是被观察者将自己的改变 “通知” 观察者,都不应该直接调用。
using System;
namespace Delegate
{
public class Heater
{
private int temperature;
public delegate void BoilHandler(int param);
public event BoilHandler BoilEvent;
public void BoilWater()
{
for (int i = 0; i <= 100; i++)
{
temperature = i;
if (temperature > 95)
{
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(); // 烧水,会自动调用注册过对象的方法
}
}
}
- 运行结果
七、.NET 框架中的委托和事件
.NET Framework 的编码规范:
- 委托类型的名称都应该以
EventHandler结束。 - 委托的原型定义:有一个
void返回值,并接受两个输入参数:一个Object类型,一个EventArgs类型(或继承自EventArgs)。 - 事件的命名为委托去掉
EventHandler之后剩余的部分。 - 继承自
EventArgs的类型应该以EventArgs结尾。
补充说明:
- 委托声明原型中的
Object类型的参数代表了Subject,也就是监视对象。 EventArgs对象包含了 Observer 所感兴趣的数据。
using System;
namespace Delegate
{
public class Heater
{
private int temperature;
public string type = "RealFire 001"; // 添加型号作为演示
public string area = "China Xian"; // 添加产地作为演示
public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);
public event BoiledEventHandler Boiled; // 声明事件
// 定义 BoiledEventArgs 类,传递给 Observer 所感兴趣的信息
public class BoiledEventArgs : EventArgs
{
public readonly int temperature;
public BoiledEventArgs(int temperature)
{
this.temperature = temperature;
}
}
// 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
protected virtual void OnBoiled(BoiledEventArgs e)
{
if (Boiled != null)
{
Boiled(this, e); // 调用所有注册对象的方法
}
}
public void BoilWater()
{
for (int i = 0; i <= 100; i++)
{
temperature = i;
if (temperature > 95)
{
// 建立 BoiledEventArgs 对象。
BoiledEventArgs e = new BoiledEventArgs(temperature);
OnBoiled(e); // 调用 OnBolied 方法
}
}
}
public class Alarm
{
public void MakeAlert(Object sender, Heater.BoiledEventArgs e)
{
Heater heater = (Heater)sender; // 这里是不是很熟悉呢?
// 访问 sender 中的公共字段
Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
}
}
public class Display
{
public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) // 静态方法
{
Heater heater = (Heater)sender;
Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
}
}
class Program
{
static void Main()
{
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater.Boiled += alarm.MakeAlert; //注册方法
heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
heater.Boiled += Display.ShowMsg; //注册静态方法
heater.BoilWater(); //烧水,会自动调用注册过对象的方法
}
}
}
}
- 运行结果:
文章参考自:C# 中的委托和事件(详解)
附加观察者模板:
using System;
using System.Collections.Generic;
namespace Delegate
{
/// <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);
}
}
class Program
{
static void Main()
{
// 具体主题角色通常用具体子类来实现
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 ();
}
}
}
- 运行结果: