C#:事件还是观察者界面?赞成/反对?
我有以下(简化的): …我很矛盾。这基本上是我用C++编写的,但是C语言有事件。我应该更改代码以使用事件,还是不使用它C#:事件还是观察者界面?赞成/反对?,c#,events,observer-pattern,C#,Events,Observer Pattern,我有以下(简化的): …我很矛盾。这基本上是我用C++编写的,但是C语言有事件。我应该更改代码以使用事件,还是不使用它 与传统的观察者界面相比,事件有哪些优点或缺点?Hmm,事件可用于实现观察者模式。事实上,使用事件可以被视为观察者模式imho的另一个实现。优点是事件更“网络化”。如果您正在设计可以拖放到窗体上的非可视组件,则可以使用设计器将它们连接起来 缺点是,一个事件只表示一个事件——对于要通知观察者的每个“事情”,您需要一个单独的事件。这实际上没有多大的实际影响,除了每个观察对象需要为每个
与传统的观察者界面相比,事件有哪些优点或缺点?Hmm,事件可用于实现观察者模式。事实上,使用事件可以被视为观察者模式imho的另一个实现。优点是事件更“网络化”。如果您正在设计可以拖放到窗体上的非可视组件,则可以使用设计器将它们连接起来 缺点是,一个事件只表示一个事件——对于要通知观察者的每个“事情”,您需要一个单独的事件。这实际上没有多大的实际影响,除了每个观察对象需要为每个事件的每个观察者保留一个引用,在存在大量观察对象的情况下会导致内存膨胀(这是他们在WPF中采用不同的方式管理观察者/观察者关系的原因之一)
在你的情况下,我认为这没什么区别。如果观察者通常对所有这些事件感兴趣,请使用观察者接口而不是单独的事件。将事件视为回调接口,其中该接口只有一个方法 仅支持您需要的挂钩事件
对于事件,您只需要为您感兴趣的事件实现处理程序。在observer接口模式中,您必须实现整个接口中的所有方法,包括为您实际上不关心处理的通知类型实现方法体。在您的示例中,您始终必须实现OnFoundDirectory和OnFoundFile,即使您只关心其中一个事件 更少的维护
事件的另一个好处是,您可以向特定类添加一个新的事件,这样它将引发事件,而不必更改所有现有的观察者。然而,如果您想向接口添加一个新方法,则必须遍历已经实现该接口的每个类,并在所有类中实现新方法。不过,对于事件,您只需要更改实际想要对添加的新事件做出响应的现有类 该模式内置于语言中,因此每个人都知道如何使用它
事件是惯用的,因为当你看到一个事件时,你知道如何使用它。通过observer接口,人们通常实现不同的注册方式来接收通知并连接observer。。不过,对于事件,一旦您学会了如何注册和使用一个(使用+=运算符),其余的都是一样的 接口的优点
我对界面没有太多的专业知识。我猜他们强迫某人实现接口中的所有方法。但是,你不能强迫某人正确地实现所有这些方法,所以我认为这没有多大价值 语法
有些人不喜欢为每个事件声明委托类型的方式。此外,.NET framework中的标准事件处理程序具有以下参数:(对象发送者、事件args args)。由于发送方未指定特定类型,所以如果要使用它,必须向下转换。这在实践中通常是好的,但感觉不太正确,因为您正在失去静态类型系统的保护。但是,如果您实现自己的事件,并且没有遵循.NET framework约定,则可以使用正确的类型,这样就不需要潜在的向下转换。接口解决方案的优点:
- 如果添加方法,现有的观察者需要实现这些方法。这意味着您不太可能忘记将现有观察者连接到新功能。当然,您可以将它们实现为空方法,这意味着您仍然可以对某些“事件”无所作为。但你不会那么容易忘记的
- 如果使用显式实现,也会以另一种方式出现编译器错误,如果删除或更改现有接口,则实现这些接口的观察器将停止编译
- 规划需要更多的考虑,因为观察者界面中的更改可能会在整个解决方案中强制实施更改,这可能需要不同的规划。由于简单事件是可选的,因此几乎不需要更改其他代码,除非其他代码对事件做出反应
- 它降低了进入的成本。说“+=neweventhandler”要比实现一个完整的接口容易得多
- 它降低了维护成本。如果你在你的类中添加了一个新的事件,这就是所有需要做的事情。如果向接口添加新事件,则必须更新代码库中的每个使用者。或者定义一个全新的接口,随着时间的推移,它会让消费者感到恼火,“我是实现IRandomEvent2还是IRandomEvent5?”
- 事件允许处理程序不基于类(即某个地方的静态方法)。没有功能上的理由强制所有事件处理程序成为实例成员
- 将一组事件分组到一个接口中就是对事件的使用方式进行假设(只是假设)
- 与原始事件相比,接口没有真正的优势
- 出于以下原因,我更喜欢基于事件的解决方案
- Java对匿名接口提供了语言支持,因此回调接口是Java中需要使用的东西
C#支持匿名委托(lambdas),因此事件是C#中要使用的东西。决定的最佳方法是:哪一个更适合这种情况。这听起来可能是一个愚蠢或无益的回答,但我认为你不应该将其中一个视为“正确的”答案
interface IFindFilesObserver
{
void OnFoundFile(FileInfo fileInfo);
void OnFoundDirectory(DirectoryInfo directoryInfo);
}
class FindFiles
{
IFindFilesObserver _observer;
// ...
}
subject.RegisterObserver(new LoggingObserver(myRealObserver));
subject.AnEvent += (sender, args) => { LogTheEvent(); realEventHandler(sender, args); };
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();
}
}
}