C#:事件还是观察者界面?优点缺点?

时间:2022-09-02 09:05:35

I've got the following (simplified):

我有以下(简化):

interface IFindFilesObserver
{
    void OnFoundFile(FileInfo fileInfo);
    void OnFoundDirectory(DirectoryInfo directoryInfo);
}

class FindFiles
{
    IFindFilesObserver _observer;

    // ...
}

...and I'm conflicted. This is basically what I would have written in C++, but C# has events. Should I change the code to use events, or should I leave it alone?

......而且我很矛盾。这基本上就是我用C ++编写的,但C#有事件。我应该更改代码以使用事件,还是应该不管它?

What are the advantages or disadvantages of events over a traditional observer interface?

与传统观察者界面相比,事件的优缺点是什么?

11 个解决方案

#1


Consider an event to be a callback interface where the interface has only one method.

将事件视为回调接口,其中接口只有一个方法。

Only hook events you need
With events you only need to implement handlers for events you're interested in handling. In the observer interface pattern, you'd have to implement all methods in the entire interface including implementing method bodies for notification types you don't actually care about handling. In your example, you always have to implement OnFoundDirectory and OnFoundFile, even if you only care about one of these events.

只需要挂钩事件您只需要为您感兴趣处理的事件实现处理程序。在观察者界面模式中,您必须在整个界面中实现所有方法,包括实现您实际上并不关心处理的通知类型的方法体。在您的示例中,您始终必须实现OnFoundDirectory和OnFoundFile,即使您只关心其中一个事件。

Less maintenance
Another good thing about events is you can add a new one to a particular class so that it will raise it, and you don't have to change every existing observer. Whereas if you want to add a new method to an interface, you have to go around every class that already implements that interface and implement the new method in all of them. With an event though, you only need to alter existing classes that actually want to do something in response to the new event you're adding.

减少维护事件的另一个好处是,您可以向特定类添加一个新的,以便它可以提升它,并且您不必更改每个现有的观察者。而如果要向接口添加新方法,则必须绕过已实现该接口的每个类并在所有接口中实现新方法。但是,对于某个事件,您只需要更改实际想要执行某些操作的现有类,以响应您要添加的新事件。

The pattern is built into the language so everybody knows how to use it
Events are idiomatic, in that when you see an event, you know how to use it. With an observer interface, people often implement different ways of registering to receive notifications and hook up the observer.. with events though, once you've learnt how to register and use one (with the += operator), the rest are all the same.

模式内置于语言中,因此每个人都知道如何使用它事件是惯用的,因为当您看到事件时,您就知道如何使用它。使用观察者界面,人们经常实现不同的注册方式来接收通知并连接观察者..但是,一旦你学会了如何注册和使用一个(使用+ =运算符),其余的都是相同。

Pros for interfaces
I haven't got many pros for interfaces. I guess they force someone to to implement all methods in the interface. But, you can't really force somebody to implement all those methods correctly, so I don't think there's a lot of value on this.

接口的优点我没有很多接口的专业人士。我猜他们强迫某人在界面中实现所有方法。但是,你不能真正强迫某人正确地实施所有这些方法,所以我认为这没有很多价值。

Syntax
Some people don't like the way you have to declare a delegate type for each event. Also, standard event handlers in the .Net framework follow have these parameters: (object sender, EventArgs args). As sender doesn't specify a particular type, you have to down-cast if you want to use it. This often is fine in practice, if feels not quite right though because you're losing the protection of the static type system. But, if you implement your own events and don't follow the .Net framework convention on this, you can use the correct type so potential down-casting isn't required.

语法有些人不喜欢为每个事件声明委托类型的方式。此外,.Net框架中的标准事件处理程序遵循以下参数:( object sender,EventArgs args)。由于发件人未指定特定类型,因此如果要使用它,则必须进行向下转换。这在实践中通常很好,如果感觉不太正确,因为你失去了对静态类型系统的保护。但是,如果您实现自己的事件并且不遵循.Net框架约定,则可以使用正确的类型,因此不需要潜在的向下转换。

#2


Hmm, events can be used to implement the Observer pattern. In fact, using events can be regarded as another implementation of the observer-pattern imho.

嗯,事件可用于实现Observer模式。事实上,使用事件可以被视为观察者模式imho的另一种实现。

#3


Pros of an interface-solution:

界面解决方案的优点:

  • If you add methods, existing observers needs to implement those methods. This means that you have less of a chance of forgetting to wire up existing observers to new functionality. You can of course implement them as empty methods which means you have the luxury of still doing nothing in response to certain "events". But you won't so easily forget.
  • 如果添加方法,现有观察者需要实现这些方法。这意味着您不太可能忘记将现有观察者连接到新功能。你当然可以将它们作为空方法来实现,这意味着你可以在某些“事件”的作用下仍然无所事事。但你不会那么容易忘记。

  • If you use explicit implementation, you'll also get compiler errors the other way, if you remove or change existing interfaces, then observers implementing them will stop compiling.
  • 如果使用显式实现,则还会以其他方式获得编译器错误,如果删除或更改现有接口,则实现它们的观察者将停止编译。

Cons:

  • More thought has to go into planning, since a change in the observer interface might enforce changes all over your solution, which might require different planning. Since a simple event is optional, little or no other code has to change unless that other code should react to the event.
  • 更多的想法必须进入规划,因为观察者界面的变化可能会在整个解决方案中强制执行更改,这可能需要不同的计划。由于简单事件是可选的,因此除非其他代码应对事件做出反应,否则很少或不需要更改其他代码。

#4


Some further benefits of events.

事件的一些进一步的好处。

  • You get proper multicast behaviour for free.
  • 您可以免费获得正确的组播行为。

  • If you change the subscribers of an event in response to that event the behaviour is well defined
  • 如果您更改事件的订阅者以响应该事件,则行为已明确定义

  • They can be introspected (reflected) easily and consistently
  • 它们可以轻松而一致地进行内省(反映)

  • Tool chain support for events (simply because they are the idiom in .net)
  • 事件的工具链支持(仅仅因为它们是.net中的成语)

  • You get the option to use the asynchronous apis it provides
  • 您可以选择使用它提供的异步apis

You can achieve all of these (except the tool chain) yourself but it's surprisingly hard. For example: If you use a member variable like a List<> to store the list of observers. If you use foreach to iterate over it then any attempt to add or remove a subscriber within one of the OnFoo() method callbacks will trigger an exception unless you write further code to deal with it cleanly.

您可以自己实现所有这些(工具链除外),但这非常困难。例如:如果使用像List <>这样的成员变量来存储观察者列表。如果你使用foreach迭代它,那么任何在一个OnFoo()方法回调中添加或删除订阅者的尝试都将触发异常,除非你编写更多代码来干净地处理它。

#5


  • Events are harder to propagate through chain of objects, for example if you use FACADE pattern or delegate work to other class.
  • 事件很难通过对象链传播,例如,如果您使用FACADE模式或将工作委托给其他类。

  • You need to be very careful with unsubscribing from events to allow object to be garbage collected.
  • 您需要非常小心地从事件中取消订阅以允许对象被垃圾收集。

  • Events are 2x time slower than simple function call, 3x slower if you do null check on every raise, and copy event delegate before null check and invocation to make it thread safe.

    事件比简单函数调用慢2倍,如果对每次加注进行空检查则慢3倍,并在空检查和调用之前复制事件委托以使其线程安全。

  • Also read MSDN about new (in 4.0) IObserver<T> interface.

    另请阅读有关新(4.0)IObserver 接口的MSDN。

Consider this example:

考虑这个例子:

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

#6


Pros are that events are more 'dot-netty'. If you are designing non-visual components that can be dropped onto a form, you can hook them up using the designer.

优点是事件更像是“网络”。如果您正在设计可以放到表单上的非可视组件,则可以使用设计器将它们连接起来。

Cons are that an event only signifies a single event - you need a separate event for each 'thing' that you want to notify the observer about. This doesn't really have much practical impact except that each observed object would need to hold a reference for every observer for every event, bloating memory in the case where there are lots of observed objects (one of the reasons they made a different way of managing the observer/observable relationship in WPF).

缺点是事件只表示单个事件 - 您需要为要通知观察者的每个'事物'单独设置事件。除了每个观察对象需要为每个事件的每个观察者保持一个参考,在有大量观察对象的情况下膨胀记忆(这是他们做出不同方式的原因之一)之外,这实际上没有太多实际影响。管理WPF中的观察者/可观察关系)。

In your case I'd argue it doesn't make much difference. If the observer would typically be interested in all those events, use an observer interface rather than separate events.

在你的情况下,我认为它没有太大的区别。如果观察者通常对所有这些事件感兴趣,请使用观察者界面而不是单独的事件。

#7


Java has language support for anonymous interfaces, so callback interfaces are the thing to use in Java.

Java具有对匿名接口的语言支持,因此回调接口是Java中使用的东西。

C# has support for anonymous delegates - lambdas - and so events are the thing to use in C#.

C#支持匿名委托 - lambdas - 因此事件是在C#中使用的东西。

#8


A benefit of interfaces is that they are easier to apply decorators to. The standard example:

接口的一个好处是它们更容易应用装饰器。标准示例:

subject.RegisterObserver(new LoggingObserver(myRealObserver));

compared to:

subject.AnEvent += (sender, args) => { LogTheEvent(); realEventHandler(sender, args); };

(I'm a big fan of the decorator pattern).

(我是装饰者模式的忠实粉丝)。

#9


I prefer an event base solution for the following reasons

我更喜欢事件基础解决方案,原因如下

  • It reduces the cost of entry. It's much easier to say "+= new EventHandler" than to implement a full fledged interface.
  • 它降低了进入成本。说“+ = new EventHandler”比实现完整的界面要容易得多。

  • It reduces maintenance costs. If you add a new event into your class that's all that needs to be done. If you add a new event to an interface you must update every single consumer in your code base. Or define an entirely new interface which over time gets annoying to consumers "Do I implement IRandomEvent2 or IRandomEvent5?"
  • 它降低了维护成本。如果您在课程中添加了一个新事件,那就是所有需要完成的事情。如果向界面添加新事件,则必须更新代码库中的每个使用者。或者定义一个全新的界面,随着时间的推移会让消费者感到烦恼“我实现IRandomEvent2还是IRandomEvent5?”

  • Events allow for handlers to be non-class based (ie a static method somewhere). There is no functional reason to force all event handlers to be an instance member
  • 事件允许处理程序基于非类(即某处的静态方法)。强制所有事件处理程序都不是实例成员是没有功能的

  • Grouping a bunch of events into an interface is making an assumption about how the events are used (and it's just that, an assumption)
  • 将一堆事件分组到一个接口中,假设事件是如何被使用的(并且就是这样,一个假设)

  • Interfaces offer no real advantage over a raw event.
  • 接口与原始事件相比没有真正的优势。

#10


The best way to decide is this: which one suits the situation better. That might sound like a silly or unhelpful answer, but I don't think you should regard one or the other as the "proper" solution.

最好的决定方法是:哪一个更适合这种情况。这可能听起来像是一个愚蠢或无益的答案,但我认为你不应该把一个或另一个视为“适当的”解决方案。

We can throw a hundred tips at you. Events are best when the observer is expected to listen for arbitrary events. An interface is best when the observer is expected to listed to all of a given set of events. Events are best when dealing with GUI apps. Interfaces consume less memory (a single pointer for multiple events). Yadda yadda yadda. A bulleted list of pros and cons is something to think about, but not a definitive answer. What you really need to do is try both of them in actual applications and get a good feel for them. Then you can choose the one that suits the situation better. Learn form doing.

我们可以向你抛出一百个提示。当观察者期望听取任意事件时,事件是最好的。当期望观察者列出所有给定事件集时,接口是最佳的。处理GUI应用程序时,事件最佳。接口消耗更少的内存(多个事件的单个指针)。 Yadda yadda yadda。一个项目符号列表的优点和缺点是需要考虑的事情,但不是一个明确的答案。你真正需要做的是在实际应用中尝试它们并获得良好的感觉。然后你可以选择更适合这种情况的那个。学习形式做。

If you have to use a single defining question, then ask yourself which better describes your situation: A set of loosely related events any of which may be used or ignored, or a set of closely related events which will all generally need to be handled by one observer. But then, I'm just describing the event model and interface model, so I'm back at square one: which one suits the situation better?

如果你必须使用一个定义问题,那么问问自己哪个更好地描述了你的情况:一组松散相关的事件,其中任何一个都可以被使用或忽略,或者一组密切相关的事件,这些事件通常都需要由一位观察员。但是,我只是在描述事件模型和界面模型,所以我回到了第一个方面:哪一个更适合这种情况?

#11


If your objects will need to be serialized in some way that retains references such as with NetDataContractSerializer or perhaps protobuf events will not be able to cross the serialization boundary. Since observer pattern relies on nothing more than just object references, it can work with this type of serialization with no problem if that is what is desired.

如果您的对象需要以某种方式序列化,以保留引用,例如使用NetDataContractSerializer或者protobuf事件将无法跨越序列化边界。由于观察者模式仅仅依赖于对象引用,因此它可以与这种类型的序列化一起使用,如果需要的话,没有问题。

Ex. You have a bunch of business objects that link to each other bidirectionally that you need to pass to a web service.

防爆。您有许多业务对象,它们需要双向链接到您需要传递给Web服务的对象。

#1


Consider an event to be a callback interface where the interface has only one method.

将事件视为回调接口,其中接口只有一个方法。

Only hook events you need
With events you only need to implement handlers for events you're interested in handling. In the observer interface pattern, you'd have to implement all methods in the entire interface including implementing method bodies for notification types you don't actually care about handling. In your example, you always have to implement OnFoundDirectory and OnFoundFile, even if you only care about one of these events.

只需要挂钩事件您只需要为您感兴趣处理的事件实现处理程序。在观察者界面模式中,您必须在整个界面中实现所有方法,包括实现您实际上并不关心处理的通知类型的方法体。在您的示例中,您始终必须实现OnFoundDirectory和OnFoundFile,即使您只关心其中一个事件。

Less maintenance
Another good thing about events is you can add a new one to a particular class so that it will raise it, and you don't have to change every existing observer. Whereas if you want to add a new method to an interface, you have to go around every class that already implements that interface and implement the new method in all of them. With an event though, you only need to alter existing classes that actually want to do something in response to the new event you're adding.

减少维护事件的另一个好处是,您可以向特定类添加一个新的,以便它可以提升它,并且您不必更改每个现有的观察者。而如果要向接口添加新方法,则必须绕过已实现该接口的每个类并在所有接口中实现新方法。但是,对于某个事件,您只需要更改实际想要执行某些操作的现有类,以响应您要添加的新事件。

The pattern is built into the language so everybody knows how to use it
Events are idiomatic, in that when you see an event, you know how to use it. With an observer interface, people often implement different ways of registering to receive notifications and hook up the observer.. with events though, once you've learnt how to register and use one (with the += operator), the rest are all the same.

模式内置于语言中,因此每个人都知道如何使用它事件是惯用的,因为当您看到事件时,您就知道如何使用它。使用观察者界面,人们经常实现不同的注册方式来接收通知并连接观察者..但是,一旦你学会了如何注册和使用一个(使用+ =运算符),其余的都是相同。

Pros for interfaces
I haven't got many pros for interfaces. I guess they force someone to to implement all methods in the interface. But, you can't really force somebody to implement all those methods correctly, so I don't think there's a lot of value on this.

接口的优点我没有很多接口的专业人士。我猜他们强迫某人在界面中实现所有方法。但是,你不能真正强迫某人正确地实施所有这些方法,所以我认为这没有很多价值。

Syntax
Some people don't like the way you have to declare a delegate type for each event. Also, standard event handlers in the .Net framework follow have these parameters: (object sender, EventArgs args). As sender doesn't specify a particular type, you have to down-cast if you want to use it. This often is fine in practice, if feels not quite right though because you're losing the protection of the static type system. But, if you implement your own events and don't follow the .Net framework convention on this, you can use the correct type so potential down-casting isn't required.

语法有些人不喜欢为每个事件声明委托类型的方式。此外,.Net框架中的标准事件处理程序遵循以下参数:( object sender,EventArgs args)。由于发件人未指定特定类型,因此如果要使用它,则必须进行向下转换。这在实践中通常很好,如果感觉不太正确,因为你失去了对静态类型系统的保护。但是,如果您实现自己的事件并且不遵循.Net框架约定,则可以使用正确的类型,因此不需要潜在的向下转换。

#2


Hmm, events can be used to implement the Observer pattern. In fact, using events can be regarded as another implementation of the observer-pattern imho.

嗯,事件可用于实现Observer模式。事实上,使用事件可以被视为观察者模式imho的另一种实现。

#3


Pros of an interface-solution:

界面解决方案的优点:

  • If you add methods, existing observers needs to implement those methods. This means that you have less of a chance of forgetting to wire up existing observers to new functionality. You can of course implement them as empty methods which means you have the luxury of still doing nothing in response to certain "events". But you won't so easily forget.
  • 如果添加方法,现有观察者需要实现这些方法。这意味着您不太可能忘记将现有观察者连接到新功能。你当然可以将它们作为空方法来实现,这意味着你可以在某些“事件”的作用下仍然无所事事。但你不会那么容易忘记。

  • If you use explicit implementation, you'll also get compiler errors the other way, if you remove or change existing interfaces, then observers implementing them will stop compiling.
  • 如果使用显式实现,则还会以其他方式获得编译器错误,如果删除或更改现有接口,则实现它们的观察者将停止编译。

Cons:

  • More thought has to go into planning, since a change in the observer interface might enforce changes all over your solution, which might require different planning. Since a simple event is optional, little or no other code has to change unless that other code should react to the event.
  • 更多的想法必须进入规划,因为观察者界面的变化可能会在整个解决方案中强制执行更改,这可能需要不同的计划。由于简单事件是可选的,因此除非其他代码应对事件做出反应,否则很少或不需要更改其他代码。

#4


Some further benefits of events.

事件的一些进一步的好处。

  • You get proper multicast behaviour for free.
  • 您可以免费获得正确的组播行为。

  • If you change the subscribers of an event in response to that event the behaviour is well defined
  • 如果您更改事件的订阅者以响应该事件,则行为已明确定义

  • They can be introspected (reflected) easily and consistently
  • 它们可以轻松而一致地进行内省(反映)

  • Tool chain support for events (simply because they are the idiom in .net)
  • 事件的工具链支持(仅仅因为它们是.net中的成语)

  • You get the option to use the asynchronous apis it provides
  • 您可以选择使用它提供的异步apis

You can achieve all of these (except the tool chain) yourself but it's surprisingly hard. For example: If you use a member variable like a List<> to store the list of observers. If you use foreach to iterate over it then any attempt to add or remove a subscriber within one of the OnFoo() method callbacks will trigger an exception unless you write further code to deal with it cleanly.

您可以自己实现所有这些(工具链除外),但这非常困难。例如:如果使用像List <>这样的成员变量来存储观察者列表。如果你使用foreach迭代它,那么任何在一个OnFoo()方法回调中添加或删除订阅者的尝试都将触发异常,除非你编写更多代码来干净地处理它。

#5


  • Events are harder to propagate through chain of objects, for example if you use FACADE pattern or delegate work to other class.
  • 事件很难通过对象链传播,例如,如果您使用FACADE模式或将工作委托给其他类。

  • You need to be very careful with unsubscribing from events to allow object to be garbage collected.
  • 您需要非常小心地从事件中取消订阅以允许对象被垃圾收集。

  • Events are 2x time slower than simple function call, 3x slower if you do null check on every raise, and copy event delegate before null check and invocation to make it thread safe.

    事件比简单函数调用慢2倍,如果对每次加注进行空检查则慢3倍,并在空检查和调用之前复制事件委托以使其线程安全。

  • Also read MSDN about new (in 4.0) IObserver<T> interface.

    另请阅读有关新(4.0)IObserver 接口的MSDN。

Consider this example:

考虑这个例子:

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

#6


Pros are that events are more 'dot-netty'. If you are designing non-visual components that can be dropped onto a form, you can hook them up using the designer.

优点是事件更像是“网络”。如果您正在设计可以放到表单上的非可视组件,则可以使用设计器将它们连接起来。

Cons are that an event only signifies a single event - you need a separate event for each 'thing' that you want to notify the observer about. This doesn't really have much practical impact except that each observed object would need to hold a reference for every observer for every event, bloating memory in the case where there are lots of observed objects (one of the reasons they made a different way of managing the observer/observable relationship in WPF).

缺点是事件只表示单个事件 - 您需要为要通知观察者的每个'事物'单独设置事件。除了每个观察对象需要为每个事件的每个观察者保持一个参考,在有大量观察对象的情况下膨胀记忆(这是他们做出不同方式的原因之一)之外,这实际上没有太多实际影响。管理WPF中的观察者/可观察关系)。

In your case I'd argue it doesn't make much difference. If the observer would typically be interested in all those events, use an observer interface rather than separate events.

在你的情况下,我认为它没有太大的区别。如果观察者通常对所有这些事件感兴趣,请使用观察者界面而不是单独的事件。

#7


Java has language support for anonymous interfaces, so callback interfaces are the thing to use in Java.

Java具有对匿名接口的语言支持,因此回调接口是Java中使用的东西。

C# has support for anonymous delegates - lambdas - and so events are the thing to use in C#.

C#支持匿名委托 - lambdas - 因此事件是在C#中使用的东西。

#8


A benefit of interfaces is that they are easier to apply decorators to. The standard example:

接口的一个好处是它们更容易应用装饰器。标准示例:

subject.RegisterObserver(new LoggingObserver(myRealObserver));

compared to:

subject.AnEvent += (sender, args) => { LogTheEvent(); realEventHandler(sender, args); };

(I'm a big fan of the decorator pattern).

(我是装饰者模式的忠实粉丝)。

#9


I prefer an event base solution for the following reasons

我更喜欢事件基础解决方案,原因如下

  • It reduces the cost of entry. It's much easier to say "+= new EventHandler" than to implement a full fledged interface.
  • 它降低了进入成本。说“+ = new EventHandler”比实现完整的界面要容易得多。

  • It reduces maintenance costs. If you add a new event into your class that's all that needs to be done. If you add a new event to an interface you must update every single consumer in your code base. Or define an entirely new interface which over time gets annoying to consumers "Do I implement IRandomEvent2 or IRandomEvent5?"
  • 它降低了维护成本。如果您在课程中添加了一个新事件,那就是所有需要完成的事情。如果向界面添加新事件,则必须更新代码库中的每个使用者。或者定义一个全新的界面,随着时间的推移会让消费者感到烦恼“我实现IRandomEvent2还是IRandomEvent5?”

  • Events allow for handlers to be non-class based (ie a static method somewhere). There is no functional reason to force all event handlers to be an instance member
  • 事件允许处理程序基于非类(即某处的静态方法)。强制所有事件处理程序都不是实例成员是没有功能的

  • Grouping a bunch of events into an interface is making an assumption about how the events are used (and it's just that, an assumption)
  • 将一堆事件分组到一个接口中,假设事件是如何被使用的(并且就是这样,一个假设)

  • Interfaces offer no real advantage over a raw event.
  • 接口与原始事件相比没有真正的优势。

#10


The best way to decide is this: which one suits the situation better. That might sound like a silly or unhelpful answer, but I don't think you should regard one or the other as the "proper" solution.

最好的决定方法是:哪一个更适合这种情况。这可能听起来像是一个愚蠢或无益的答案,但我认为你不应该把一个或另一个视为“适当的”解决方案。

We can throw a hundred tips at you. Events are best when the observer is expected to listen for arbitrary events. An interface is best when the observer is expected to listed to all of a given set of events. Events are best when dealing with GUI apps. Interfaces consume less memory (a single pointer for multiple events). Yadda yadda yadda. A bulleted list of pros and cons is something to think about, but not a definitive answer. What you really need to do is try both of them in actual applications and get a good feel for them. Then you can choose the one that suits the situation better. Learn form doing.

我们可以向你抛出一百个提示。当观察者期望听取任意事件时,事件是最好的。当期望观察者列出所有给定事件集时,接口是最佳的。处理GUI应用程序时,事件最佳。接口消耗更少的内存(多个事件的单个指针)。 Yadda yadda yadda。一个项目符号列表的优点和缺点是需要考虑的事情,但不是一个明确的答案。你真正需要做的是在实际应用中尝试它们并获得良好的感觉。然后你可以选择更适合这种情况的那个。学习形式做。

If you have to use a single defining question, then ask yourself which better describes your situation: A set of loosely related events any of which may be used or ignored, or a set of closely related events which will all generally need to be handled by one observer. But then, I'm just describing the event model and interface model, so I'm back at square one: which one suits the situation better?

如果你必须使用一个定义问题,那么问问自己哪个更好地描述了你的情况:一组松散相关的事件,其中任何一个都可以被使用或忽略,或者一组密切相关的事件,这些事件通常都需要由一位观察员。但是,我只是在描述事件模型和界面模型,所以我回到了第一个方面:哪一个更适合这种情况?

#11


If your objects will need to be serialized in some way that retains references such as with NetDataContractSerializer or perhaps protobuf events will not be able to cross the serialization boundary. Since observer pattern relies on nothing more than just object references, it can work with this type of serialization with no problem if that is what is desired.

如果您的对象需要以某种方式序列化,以保留引用,例如使用NetDataContractSerializer或者protobuf事件将无法跨越序列化边界。由于观察者模式仅仅依赖于对象引用,因此它可以与这种类型的序列化一起使用,如果需要的话,没有问题。

Ex. You have a bunch of business objects that link to each other bidirectionally that you need to pass to a web service.

防爆。您有许多业务对象,它们需要双向链接到您需要传递给Web服务的对象。