Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#:事件还是观察者界面?赞成/反对?_C#_Events_Observer Pattern - Fatal编程技术网

C#:事件还是观察者界面?赞成/反对?

C#:事件还是观察者界面?赞成/反对?,c#,events,observer-pattern,C#,Events,Observer Pattern,我有以下(简化的): …我很矛盾。这基本上是我用C++编写的,但是C语言有事件。我应该更改代码以使用事件,还是不使用它 与传统的观察者界面相比,事件有哪些优点或缺点?Hmm,事件可用于实现观察者模式。事实上,使用事件可以被视为观察者模式imho的另一个实现。优点是事件更“网络化”。如果您正在设计可以拖放到窗体上的非可视组件,则可以使用设计器将它们连接起来 缺点是,一个事件只表示一个事件——对于要通知观察者的每个“事情”,您需要一个单独的事件。这实际上没有多大的实际影响,除了每个观察对象需要为每个

我有以下(简化的):

…我很矛盾。这基本上是我用C++编写的,但是C语言有事件。我应该更改代码以使用事件,还是不使用它


与传统的观察者界面相比,事件有哪些优点或缺点?

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();
                  }
              }
          }