前两天写了篇 delegate 与 event 的比较,其中有个特别大的错误由Cavingdeep兄给予指正,在此再次表示感谢!
本来准备这两天整理一下,重新写一遍。昨天上 blog 一看,Cavingdeep兄和装配脑袋兄在那篇 blog 上就 Observer 与 event 各自发表了一长串评论;)于是临时决定写一篇 .net event (简称 event,下同) 与 Observer 的比较。不过,这次我不在正文中包含分析和结论(充分汲取上次的教训,哈哈),而在后面的评论中逐步想到什么补充什么。同时也欢迎大家一起来讨论,尤其是Cavingdeep和装配脑袋二兄;)
前两天写了篇 delegate 与 event 的比较,其中有个特别大的错误由Cavingdeep兄给予指正,在此再次表示感谢!
本来准备这两天整理一下,重新写一遍。昨天上 blog 一看,Cavingdeep兄和装配脑袋兄在那篇 blog 上就 Observer 与 event 各自发表了一长串评论;)于是临时决定写一篇 .net event (简称 event,下同) 与 Observer 的比较。不过,这次我不在正文中包含分析和结论(充分汲取上次的教训,哈哈),而在后面的评论中逐步想到什么补充什么。同时也欢迎大家一起来讨论,尤其是Cavingdeep和装配脑袋二兄;)
老规矩,拿代码说话吧:
using System;
using System.Collections.Generic;
namespace EventAndObserver
{
【区别】1. 底层支撑#region 【区别】1. 底层支撑
// Observer 使用一个基类(Subject)和一个接口(IObserver)
// 其中 IObserver.Update 和 Subject.Notify 不同人有不同的实现版本,但总体思想是一致的。
public interface IObserver
{
void Update(Subject who, string what);
}
public abstract class Subject
{
ICollection<IObserver> _observers = new List<IObserver>();
public void Attach(IObserver observer)
{
_observers.Add(observer);
}
public void Detach(IObserver observer)
{
_observers.Remove(observer);
}
protected void Notify(string what)
{
foreach (IObserver observer in _observers)
{
observer.Update(this, what);
}
}
}
// event 则是.Net framework 提供的 delegate、event 等等实现
#endregion
【区别】2. 事件发布者#region 【区别】2. 事件发布者
public class Product : Subject
{
string _name;
double _price;
public string Name
{
get { return _name; }
set
{
_name = value;
【区别】2.1. 事件通知方式#region 【区别】2.1. 事件通知方式
// Observer 调用基类中实现的Notify方法
Notify("Name");
// event 则是直接调用,而在event的基类MulticastDelegate的实现也会有一个与上面Notify类似的foreach语句
if (null != NameChanged) NameChanged(this, EventArgs.Empty);
#endregion
}
}
public double Price
{
get { return _price; }
set
{
_price = value;
【区别】2.1.#region 【区别】2.1.
Notify("Price");
if (null != PriceChanged) PriceChanged(this, EventArgs.Empty);
#endregion
}
}
【区别】2.2. 由于事件通知方式不同带来的额外区别#region 【区别】2.2. 由于事件通知方式不同带来的额外区别
// Observer 需要该 class 继承于 Subject
// event 则在该 class 中直接定义相应的“事件”
public event EventHandler NameChanged;
public event EventHandler PriceChanged;
#endregion
}
#endregion
【区别】3. 事件响应者#region 【区别】3. 事件响应者
public class Program
{
【区别】3.1. 事件响应代码的书写#region 【区别】3.1. 事件响应代码的书写
// Observer 需要定义额外的 class,并在IObserver.Update的实现中书写事件响应代码
public class NameObserver : IObserver
{
public void Update(Subject who, string what)
{
if ((what == "Name") && (who is Product))
Console.WriteLine("The product's name is changed to " + ((Product)who).Name);
}
}
public class PriceObserver : IObserver
{
public void Update(Subject who, string what)
{
if ((what == "Price") && (who is Product))
Console.WriteLine("The product's price is changed to " + ((Product)who).Price);
}
}
// event 则在符合相应 event 签名的方法(method)中书写事件响应代码
void p_PriceChanged(object sender, EventArgs e)
{
if (sender is Product)
Console.WriteLine("The product's name is changed to " + ((Product)sender).Name);
}
void p_NameChanged(object sender, EventArgs e)
{
if (sender is Product)
Console.WriteLine("The product's price is changed to " + ((Product)sender).Price);
}
#endregion
void TestMain()
{
Product p = new Product();
【区别】3.1.#region 【区别】3.1.
// Observer 由于使用了额外的 class,还需要声明和创建实例,而event则不需要额外处理
NameObserver no = new NameObserver();
PriceObserver po = new PriceObserver();
#endregion
【区别】3.2. Attach和Detach的方式#region 【区别】3.2. Attach和Detach的方式
// Observer
p.Attach(no);
p.Attach(po);
// event
p.NameChanged += p_NameChanged;
p.PriceChanged += p_PriceChanged;
#endregion
p.Name = "Book1";
p.Price = 132.8;
【区别】3.2.#region 【区别】3.2.
// Observer
p.Detach(no);
p.Detach(po);
// event
p.NameChanged -= p_NameChanged;
p.PriceChanged -= p_PriceChanged;
#endregion
}
}
#endregion
}
using System.Collections.Generic;
namespace EventAndObserver
{
【区别】1. 底层支撑#region 【区别】1. 底层支撑
// Observer 使用一个基类(Subject)和一个接口(IObserver)
// 其中 IObserver.Update 和 Subject.Notify 不同人有不同的实现版本,但总体思想是一致的。
public interface IObserver
{
void Update(Subject who, string what);
}
public abstract class Subject
{
ICollection<IObserver> _observers = new List<IObserver>();
public void Attach(IObserver observer)
{
_observers.Add(observer);
}
public void Detach(IObserver observer)
{
_observers.Remove(observer);
}
protected void Notify(string what)
{
foreach (IObserver observer in _observers)
{
observer.Update(this, what);
}
}
}
// event 则是.Net framework 提供的 delegate、event 等等实现
#endregion
【区别】2. 事件发布者#region 【区别】2. 事件发布者
public class Product : Subject
{
string _name;
double _price;
public string Name
{
get { return _name; }
set
{
_name = value;
【区别】2.1. 事件通知方式#region 【区别】2.1. 事件通知方式
// Observer 调用基类中实现的Notify方法
Notify("Name");
// event 则是直接调用,而在event的基类MulticastDelegate的实现也会有一个与上面Notify类似的foreach语句
if (null != NameChanged) NameChanged(this, EventArgs.Empty);
#endregion
}
}
public double Price
{
get { return _price; }
set
{
_price = value;
【区别】2.1.#region 【区别】2.1.
Notify("Price");
if (null != PriceChanged) PriceChanged(this, EventArgs.Empty);
#endregion
}
}
【区别】2.2. 由于事件通知方式不同带来的额外区别#region 【区别】2.2. 由于事件通知方式不同带来的额外区别
// Observer 需要该 class 继承于 Subject
// event 则在该 class 中直接定义相应的“事件”
public event EventHandler NameChanged;
public event EventHandler PriceChanged;
#endregion
}
#endregion
【区别】3. 事件响应者#region 【区别】3. 事件响应者
public class Program
{
【区别】3.1. 事件响应代码的书写#region 【区别】3.1. 事件响应代码的书写
// Observer 需要定义额外的 class,并在IObserver.Update的实现中书写事件响应代码
public class NameObserver : IObserver
{
public void Update(Subject who, string what)
{
if ((what == "Name") && (who is Product))
Console.WriteLine("The product's name is changed to " + ((Product)who).Name);
}
}
public class PriceObserver : IObserver
{
public void Update(Subject who, string what)
{
if ((what == "Price") && (who is Product))
Console.WriteLine("The product's price is changed to " + ((Product)who).Price);
}
}
// event 则在符合相应 event 签名的方法(method)中书写事件响应代码
void p_PriceChanged(object sender, EventArgs e)
{
if (sender is Product)
Console.WriteLine("The product's name is changed to " + ((Product)sender).Name);
}
void p_NameChanged(object sender, EventArgs e)
{
if (sender is Product)
Console.WriteLine("The product's price is changed to " + ((Product)sender).Price);
}
#endregion
void TestMain()
{
Product p = new Product();
【区别】3.1.#region 【区别】3.1.
// Observer 由于使用了额外的 class,还需要声明和创建实例,而event则不需要额外处理
NameObserver no = new NameObserver();
PriceObserver po = new PriceObserver();
#endregion
【区别】3.2. Attach和Detach的方式#region 【区别】3.2. Attach和Detach的方式
// Observer
p.Attach(no);
p.Attach(po);
// event
p.NameChanged += p_NameChanged;
p.PriceChanged += p_PriceChanged;
#endregion
p.Name = "Book1";
p.Price = 132.8;
【区别】3.2.#region 【区别】3.2.
// Observer
p.Detach(no);
p.Detach(po);
// event
p.NameChanged -= p_NameChanged;
p.PriceChanged -= p_PriceChanged;
#endregion
}
}
#endregion
}