C# 委托 事件 观察者模式 总结

主要内容转自http://www.tracefact.net/csharp-programming/delegates-and-events-in-csharp.aspx

根据自己理解进行了整理

----------------------------------
委托
----------------------------------
委托,类似于c中的函数指针,在C#中是一种类型,和string类型一样。(委托实质是一个类)委托可以使用=,=+,=-,new运算符,将多个函数赋值到委托。委托可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。代码如下:

private static void EnglishGreeting(string name) {
	Console.WriteLine("Morning, " + name);
}

private static void ChineseGreeting(string name) {
	Console.WriteLine("早上好, " + name);
}

delegate void GreetingDelegate(string name);//定义一个委托类型
GreetingDelegate delegate1;// 声明一个委托类型变量
delegate1 = EnglishGreeting;// 先给委托类型的变量赋值
delegate1 += ChineseGreeting;// 给此委托变量再绑定一个方法

// 调用委托
delegate1 ("Jimmy Zhang");// 将先后调用 EnglishGreeting 与 ChineseGreeting 方法

注意这里,第一次用的“=”,是赋值的语法;第二次,用的是“+=”,是绑定的语法。如果第一次就使用“+=”,将出现“使用了未赋值的局部变量”的编译错误。使用该委托时,绑定的函数会依次执行。上面代码可以简化为:

GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);
delegate1 += ChineseGreeting;   // 给此委托变量再绑定一个方法
----------------------------------
事件
----------------------------------
委托作为一个类型,在一个类中可能会有一个委托类型成员对象。将该委托类型成员对象设置public就严重破坏对象的封装性。但如果设置为private就无法为该委托类型成员对象赋值。因此,使用C#的属性对委托类型成员对象进行封装,就可解决该问题。为了简化属性封装,产生了event关键字。代码如下:
public class GreetingManager{
	// 声明一个事件(属性封装委托)
	public event GreetingDelegate MakeGreet;

	public void GreetPeople(string name) {
		MakeGreet(name);
	}
}
----------------------------------
Observer设计模式(观察者模式)
----------------------------------
观察者模式包含两个对象,一个是subject(被观察对象),一个是Observer(观察者对象)。
定义:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。
示例代码:
// 热水器
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();   //烧水,会自动调用注册过对象的方法
	}
}

说明:Heater类有BoilEvent对象(public),对外提供BoilEvent事件通知。需要获得BoilEvent事件,只需要注册即可。

----------------------------------

.Net Framework中的委托与事件
----------------------------------
 .Net Framework的编码规范:
 1、委托类型的名称都应该以EventHandler结束
 2、委托的原型定义有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)


 其中这个Object类型就是观察者模式中的subject(被观察对象),其作用是为了Observer(观察者对象)注册的方法可以访问subject(被观察对象)的public成员。上面代码例子中,subject(被观察对象)就是heater,Observer(观察者对象)注册的方法就是alarm.MakeAlert或者Display.ShowMsg

 
 其中EventArgs对象包含了Observer所感兴趣的数据,上面代码例子中就是MakeAlert(int param)函数中的param,也就是heater中的temperature
 
 3、事件的命名为 委托去掉 EventHandler之后剩余的部分
 4、继承自EventArgs的类型应该以EventArgs结尾
 
 按照上述规范,改写上部分代码

// 热水器
public class Heater
{
	private int temperature;
	public string type = "RealFire 001";       // 添加型号作为Object sender访问演示
	public string area = "China Xian";         // 添加产地作为Object sender访问演示
	public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);//定义委托
	public event BoiledEventHandler Boiled; //声明事件

	// 定义BoiledEventArgs类,作为EventArgs访问演示
	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);
		Console.WriteLine();
	}
}

// 显示器
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);
		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();   //烧水,会自动调用注册过对象的方法
	}
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值