1.委托delegate
委托实际上就是引用,用于引用函数,相当于C++种的函数指针,但是委托是类型安全的,委托定义了函数的全部细节--返回值类型 参数细节 委托实际上就是相应函数的代理 虽然委托看起来是多此一举 但是委托是类型安全的,委托可以调用任何跟委托关联的方法,并且委托是事件的基础,一个委托代表了一类方法 可扩展性大大增强
有了委托你就可以把方法看作像常数一样,而委托就是该常数类型的变量.
从这个角度看来用于声明事件的委托就是声明这个事件触发以后所调用的方法的标签或者特征.只有符合该标签(参数个数和参数类型)的方法才可以做为该用于该事件的回调.
一个事件触发了,你可能需要用多个方法处理该事件或者说该事件调用了多个方法(每个事件的实例都有一个需要调用的方法列表,当事件触发它会逐个调用列表中的每个方法)
通过使用委托你可以实现对一类方法的封装.
打个比方:如果你骑自行车,你需要有骑自行车的方法DriveBike().如果你骑摩托车你需要有骑摩托车的方法.现在你有一个方法DriveMoto.现在你需要定义一个方法,实现你骑(自行车或者摩托车)到某地DriveTo(地点,骑的方式)
骑的方式这里其实就是委托.在使用的时候,如果你是骑自行车你就用DriveBike实例化委托的实例带入DriveTo方法,如果你骑摩托车你就用DriveMoto实例化"骑的方式"这个委托带入DriveTo方法.
多播委托
如果调用多播委托就可以按顺连续序调用多个方法,为此多播委托的签名就必须返回void,实际上如果编译器发现摸个委托返回void就会自动假定这是一个多播委托,如果使用多播委托就应该注意同一个委托调用方法链的顺序并未正式定义,因此应避免编写以任意特定顺序调用方法的代码
匿名方法
在定义test时并不是传递了已知的方法名,而是使用了一个代码块
public delegate testDelegate (string s);
testDelegate test=delegate(string s)
{
Console.WriteLine(s);
}
2. 事件 Event (Observer观察者设计模式)
Observer设计模式中主要包括如下两类对象:
Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。
监视对象并不关心谁在监视它,当达到满足条件后它会把事件广播出去(OnAction函数)广播的内容包括谁触发了事件和监视者所关心的一些信息(this,e)在本例中触发监视对象的是当水达到95度时候调用OnAction函数,而监视者关心的信息是温度temperature
一个监视对象可以被很多观察者所监视,这也是观察者所不关心的,这种模式充分体现了delegate的优越性,由于被监视者不关心谁在监视它,所以只要满足委托所定义的细节的函数都可以作为监视者观察对象 假设没有委托模式 监视对象必须在函数体内连接监视对象 在温度达到标准后必须一一通知监视者 并且当监视者增加后 必须在监视对象类中重写函数以增加监视对象的调用 这大大降低了函数的可扩展性
Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式
Net Framework的编码规范:
委托类型的名称都应该以EventHandler结束。
委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
事件的命名为 委托去掉 EventHandler之后剩余的部分。
继承自EventArgs的类型应该以EventArgs结尾。
再做一下说明:
委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是 Heater(热水器)。回调函数(比如Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。
EventArgs 对象包含了Observer所感兴趣的数据,在本例中是temperature。
上面这些其实不仅仅是为了编码规范而已,这样也使得程序有更大的灵活性。比如说,如果我们不光想获得热水器的温度,还想在Observer端(警报器或者显示器)方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得很麻烦,而如果我们将热水器的引用传给警报器的方法,就可以在方法中直接访问热水器了。
using System;
using System.Collections.Generic;
using System.Text;
namespace Delegate
{
// 热水器
public class Heater
{
private int temperature;
public string type = "RealFire 001"; // 添加型号作为演示
public string area = "China Xian"; // 添加产地作为演示
//声明委托
public delegate void BoiledEventHandler(Object sender, BoliedEventArgs e);
public event BoiledEventHandler Boiled; //声明事件
// 定义BoliedEventArgs类,传递给Observer所感兴趣的信息(subject 监视对象)
public class BoliedEventArgs : EventArgs
{
public readonly int temperature;
public BoliedEventArgs(int temperature)
{
this.temperature = temperature;
}
}
// 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
protected virtual void OnBolied(BoliedEventArgs e)//事件发生模型
{
if (Boiled != null)
{ // 如果有对象注册
Boiled(this, e); // 调用所有注册对象的方法
}
}
// 烧水。
public void BoilWater()
{
for (int i = 0; i <= 100; i++)
{
temperature = i;
if (temperature > 95)
{
//建立BoliedEventArgs 对象。
BoliedEventArgs e = new BoliedEventArgs(temperature);
OnBolied(e); // 调用 OnBolied方法
}
}
}
}
// 警报器(observer观察着模型)
public class Alarm
{
public void MakeAlert(Object sender, Heater.BoliedEventArgs e)
{
Heater heater = (Heater)sender; //这里是不是很熟悉呢?
//访问 sender 中的公共字段
Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
Console.WriteLine();
}
}
// 显示器(observer观察着模型)
public class Display
{
public static void ShowMsg(Object sender, Heater.BoliedEventArgs e)
{ //静态方法
Heater heater = (Heater)sender;
Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
Console.WriteLine();
}
}
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(); //烧水,会自动调用注册过对象的方法
}
}
} |