Can I say that the relation between events and delegates adopts composite pattern?

二次信任 提交于 2020-12-08 16:13:23

问题


An event can contain many handlers which are defined using delegate, my current understanding is that delegate is just an abstraction of function pointer. Since an event, which associated with a delegate type, can add / remove many delegates into it, and composite pattern treats a composite object the same as the terminal object, so the idea is:

composite.onTriggered();
// Internally:
// foreach(handler in composite)
// {
//     handler.onTriggered();
// }

will in turn call every handlers managed by the composite.

But it seems like public event EventHandler ThresholdReached does not define a composite, see my comment in the code below

class Counter
{
    public event EventHandler ThresholdReached;

    protected virtual void OnThresholdReached(EventArgs e)
    {
        EventHandler handler = ThresholdReached; // So what's the point of this line?
        handler?.Invoke(this, e);
        // Why not just:
     // ThresholdReached?.Invoke(this, e);
    } 

    // provide remaining implementation for the class
}

Am I correct about the idea in abstract level? If not could you provide any correction(s)?


回答1:


Directly answering your question, I would say: No, there is no relation between events and delegates adopting the composite pattern. Delegates design yes, it follows the composite pattern. Events not. (Moreover, notice that you do not need events to take advantage of delegates. (see DelegateBased bellow)) (I will answer your comment about "So what's the point of this line?" at the end as a side note)

Nevertheless, the Delegate type itself follows the composite approach in terms that “The composite pattern describes a group of objects that are treated the same way as a single instance of the same type of object.”.

In turn, as @Flydog57 and @mark-seemann have already mentioned the .NET event model follows the observer pattern.

The relation between Events and Delegates regards the Event declaration that may require a Delegate type (the TypeSpec), as it is stated in the section II.18 Defining events of ECMA-335 (CLI) Partitions I to VI (the standard):

In typical usage, the TypeSpec (if present) identifies a delegate whose signature matches the arguments passed to the event’s fire method.

To make it clear, check the following two equivalent examples where EventBased uses events without a delegate field and DelegateBased uses a delegate field without events. Notice that I say distinctly delegate field or delegate type. They are not the same. Both examples need a delegate type which is declared as the following for this example:

delegate void Observer();

You may run both examples with:

var subject = new DelegateBased(); // replace it with: var subject = new EventBased();
Observer foo = () => Console.Write("Foo");
Observer bar = () => Console.Write("Bar");
subject.RegisterObserver(foo); // subject.Caller += foo;
subject.RegisterObserver(bar); // subject.Caller += bar;
subject.Notify(); // prints: FooBar
Console.WriteLine();
subject.UnregisterObserver(foo); // subject.Caller -= foo;
subject.Notify(); // prints: Bar

Next, the two implementations of EventBased and DelegateBased that use names according to the example of Observer Pattern in Wikipedia

class EventBased {
  private List<Observer> observers = new List<Observer>();
  public event Observer Caller {
    add { RegisterObserver(value); }
    remove { UnregisterObserver(value); }
  }
  public void Notify() { foreach (var caller in observers) caller(); }
    
  public void RegisterObserver(Observer val) {  observers.Add(val); }
    
  public void UnregisterObserver(Observer val) { observers.Remove(val); }
}
class DelegateBased {
  private Observer observers; // delegate field without events
    
  public void Notify() { observers(); }

  public void RegisterObserver(Observer val) { 
    observers = (Observer) Delegate.Combine(observers, val); // <=> observers += val
  }
  public void UnregisterObserver(Observer val) {
    observers = (Observer) Delegate.Remove(observers, val); // <=> observers -= val
  }
}

Regarding your comment about:

EventHandler handler = ThresholdReached; // So what's the point of this line?
handler?.Invoke(this, e);

The reason it is clearly identified by Jeffrey Richter in its masterpiece "Clr via C#" in Chapter 11 - Events at "Raising an Event in a Thread-Safe Way" (see the NewMail as the ThresholdReached of your example) where it states:

The problem with the OnNewMail method is that the thread could see that NewMail is not null, and then, just before invoking NewMail, another thread could remove a delegate from the chain making NewMail null, resulting in a NullReferenceException being thrown.




回答2:


As Flydog57 points out, the .NET event model is essentially the Observer pattern built into the language, just like IEnumerable and foreach implements the Iterator pattern.

The patterns in the Gang of Four book are, however, at various levels of abstraction. I'm not sure that this was clear to anyone in 1994, but with decades of use it's becoming increasingly clear (to me, at least) that some of those patterns are more general than others. One such pattern is the Adapter pattern, where you can view the Decorator pattern as a degenerate specialisation.

Another such pattern is Composite. You can view some of the other patterns in the books as specialisations of Composite. Not only Observer, but also Command and State (at least as described in the book); possibly others.

I think that your intuition is correct. While events are most specifically patterned after the Observer pattern, you can also think of it as a Composite. This may be clearer if we consider Reactive Extensions (Rx) and the IObserver<T> interface instead of .NET events. IIRC, Rx defines conversions between .NET events and its own model.

More generally, every API that gives rise to a monoid can be modelled as a Composite. Since events return no data (they have void method signatures) they form a monoid. Therefore, you can also view them as an instance of the Composite design pattern.



来源:https://stackoverflow.com/questions/64906053/can-i-say-that-the-relation-between-events-and-delegates-adopts-composite-patter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!