Rog*_*mbe 58 c# events observer-pattern
我有以下(简化):
interface IFindFilesObserver
{
void OnFoundFile(FileInfo fileInfo);
void OnFoundDirectory(DirectoryInfo directoryInfo);
}
class FindFiles
{
IFindFilesObserver _observer;
// ...
}
Run Code Online (Sandbox Code Playgroud)
......而且我很矛盾.这基本上就是我用C++编写的,但C#有事件.我应该更改代码以使用事件,还是应该不管它?
与传统观察者界面相比,事件的优缺点是什么?
Sco*_*ham 67
将事件视为回调接口,其中接口只有一个方法.
只有您需要的钩子事件
使用事件,您只需要为您感兴趣的事件实现处理程序.在观察者界面模式中,您必须在整个界面中实现所有方法,包括实现您实际上并不关心处理的通知类型的方法体.在您的示例中,您始终必须实现OnFoundDirectory和OnFoundFile,即使您只关心其中一个事件.
减少维护
事件的另一个好处是,您可以向特定类添加一个新的,以便它可以提升它,并且您不必更改每个现有的观察者.而如果要向接口添加新方法,则必须绕过已实现该接口的每个类并在所有接口中实现新方法.但是,对于事件,您只需要更改实际想要执行某些操作的现有类以响应您要添加的新事件.
模式内置于语言中,因此每个人都知道如何使用它
事件是惯用的,因为当您看到事件时,您就知道如何使用它.使用观察者界面,人们经常实现不同的注册方式来接收通知并连接观察者......但是,一旦你学会了如何注册和使用一个(使用+ =运算符),其余的都是相同.
接口的优点
我没有很多接口的专业人士.我猜他们强迫某人在界面中实现所有方法.但是,你不能真正强迫某人正确地实施所有这些方法,所以我认为这没有很多价值.
语法
有些人不喜欢为每个事件声明委托类型的方式.此外,.Net框架中的标准事件处理程序遵循以下参数:( object sender,EventArgs args).由于发件人未指定特定类型,因此如果要使用它,则必须进行向下转换.这在实践中通常很好,如果感觉不太正确,因为你正在失去对静态类型系统的保护.但是,如果您实现自己的事件并且不遵循.Net框架约定,则可以使用正确的类型,因此不需要潜在的向下转换.
Fre*_*els 29
嗯,事件可用于实现Observer模式.事实上,使用事件可以被视为观察者模式imho的另一种实现.
界面解决方案的优点:
缺点:
事件的一些进一步好处.
你可以自己实现所有这些(工具链除外),但这是非常困难的.例如:如果使用像List <>这样的成员变量来存储观察者列表.如果你使用foreach迭代它,那么任何在一个OnFoo()方法回调中添加或删除订阅者的尝试都将触发异常,除非你编写更多代码来干净地处理它.
事件比简单函数调用慢2倍,如果对每次加注进行空检查,则慢3倍,并在null检查和调用之前复制事件委托以使其线程安全.
考虑这个例子:
using System;
namespace Example
{
//Observer
public class SomeFacade
{
public void DoSomeWork(IObserver notificationObject)
{
Worker worker = new Worker(notificationObject);
worker.DoWork();
}
}
public class Worker
{
private readonly IObserver _notificationObject;
public Worker(IObserver notificationObject)
{
_notificationObject = notificationObject;
}
public void DoWork()
{
//...
_notificationObject.Progress(100);
_notificationObject.Done();
}
}
public interface IObserver
{
void Done();
void Progress(int amount);
}
//Events
public class SomeFacadeWithEvents
{
public event Action Done;
public event Action<int> Progress;
private void RaiseDone()
{
if (Done != null) Done();
}
private void RaiseProgress(int amount)
{
if (Progress != null) Progress(amount);
}
public void DoSomeWork()
{
WorkerWithEvents worker = new WorkerWithEvents();
worker.Done += RaiseDone;
worker.Progress += RaiseProgress;
worker.DoWork();
//Also we neede to unsubscribe...
worker.Done -= RaiseDone;
worker.Progress -= RaiseProgress;
}
}
public class WorkerWithEvents
{
public event Action Done;
public event Action<int> Progress;
public void DoWork()
{
//...
Progress(100);
Done();
}
}
}
Run Code Online (Sandbox Code Playgroud)
最好的决定方法是:哪一个更适合具体情况。这听起来可能是一个愚蠢或无益的答案,但我认为您不应该将其中一个视为“正确”的解决方案。
我们可以向您提供一百个提示。当观察者期望监听任意事件时,事件是最好的。当观察者希望列出所有给定的事件集时,界面是最好的。处理 GUI 应用程序时,事件是最好的选择。接口消耗更少的内存(多个事件的单个指针)。亚达亚达亚达。优点和缺点的项目符号列表值得考虑,但不是明确的答案。您真正需要做的是在实际应用中尝试它们并获得良好的感受。然后你可以选择更适合情况的一种。学习形式实践。
如果您必须使用单个定义问题,那么问问自己哪个更能描述您的情况:一组松散相关的事件,其中任何一个都可以使用或忽略,或者一组密切相关的事件,通常都需要由一名观察员。但是,我只是描述了事件模型和接口模型,所以我又回到了第一个问题:哪一个更适合这种情况?
| 归档时间: |
|
| 查看次数: |
19960 次 |
| 最近记录: |