委托与事件
.net中委托与事件的编程规范:
1.委托的名称都应该以EventHandler结束
2.委托的原型定义:有一个void返回值.并接受两个输入参数:一个Object类型的参数,一个EventArgs类型(或继承自EventArgs)
3.事件的命名为 委托去掉EventHandler之后的部分
4.继承自EventArgs的类型应该以EventArgs结尾
说明:
1.委托中的Object类型的参数为引发事件的对象.
2.EventArgs对象应包含事件处理对象所需要的数据.
见下例,对下例该如何改造:
public class Heater { public int temp=0; public event BoilHandler BoilEvent; public void BoilWater() { for (; temp <= 100; temp++) { if (temp >= 96) { if (BoilEvent != null) { BoilEvent(temp); } } } } } public delegate void BoilHandler(int temp); public class Alarm { public void MakeAlert(int temp) { HttpContext.Current.Response.Write("警告:现在温度是" + temp.ToString() + "<br/>"); } } public class Display { public void ShowMsg(int temp) { HttpContext.Current.Response.Write("提示:水开了.温度是" + temp.ToString() + "<br/>"); } }
页面调用:
protected void Page_Load(object sender, EventArgs e) { Heater heater = new Heater(); Alarm alarm = new Alarm(); Display display = new Display(); heater.BoilEvent += alarm.MakeAlert; heater.BoilEvent += display.ShowMsg; heater.BoilWater(); }
若使用委托,按照编码规范,改造如下:
public class Heater { public int temp; public Heater(int temp) { this.temp = temp; } public delegate void BoilEventHandler(Object sender,BoiledEventArgs e); public event BoilEventHandler Boil; public void BoilWater() { for (; temp <= 100; temp++) { if (temp >= 96) { BoiledEventArgs e = new BoiledEventArgs(temp); if (Boil != null) { Boil(this, e); } } } } } public class BoiledEventArgs : EventArgs { public int temp; public BoiledEventArgs(int temp) { this.temp = temp; } } public class Alarm { public void MakeAlert(Object sender,BoiledEventArgs e) { Heater heater = (Heater)sender; HttpContext.Current.Response.Write("警告:现在温度是" + heater.temp.ToString() + "<br/>"); } }
若不使用委托,用观察者模式,改造如下:
public class HeaterSubject { int temp=0; ArrayList observers; public HeaterSubject() { observers = new ArrayList(); } public void AddObserver(Observer observer) { this.observers.Add(observer); } public void RemoveObserver(Observer observer) { observers.Remove(observer); } public void BoilWater() { for (; temp <= 100; temp++) { if (temp >= 96) { Notice(temp); } } } void Notice(int temp) { foreach (Observer observer in observers) { observer.Update(temp); } } } public interface Observer { void Update(int temp); } public class AlarmObserver : Observer { public void Update(int temp) { HttpContext.Current.Response.Write("警告:现在温度是" + temp.ToString() + "<br/>"); } } public class DisplayObserver : Observer { public void Update(int temp) { HttpContext.Current.Response.Write("提示:水开了.温度是" + temp.ToString() + "<br/>"); } }
比较:
使用委托,则事件处理对象的方法名可以和委托不一致,但是签名需匹配.
使用观察者模式,事件处理对象需实现同一个接口.
何时使用委托?何时使用接口?
在以下情况中使用委托:
当使用事件设计模式时。
当封装静态方法可取时。
当调用方不需要访问实现该方法的对象中的其他属性、方法或接口时。
需要方便的组合。
当类可能需要该方法的多个实现时。
在以下情况中使用接口:
当存在一组可能被调用的相关方法时。
当类只需要方法的单个实现时。
当使用接口的类想要将该接口强制转换为其他接口或类类型时。
当正在实现的方法链接到类的类型或标识时:例如比较方法