José F. Romaniello

Las aventuras y desventuras de un codificador.

The idea behind the Event Aggregation is to build loosely coupled components. In this post I’d like to introduce you a simple scenario for event aggregation.

Imagine that you are building the Microsoft Sql Server Management Studio Express, the “shell” of this program looks as follows:

This shell has a Create Connection panel and an Objects Explorer dialog. When the user press the Connect button, the connection must be added to the object explorer panel.

We will focus in this simple question:

Who is responsible to notify to the Object Explorer panel that a connection has been added?

I will not talk about MVVM, MVP, WPF and Winforms, this is pure theoretically.

Option A: direct notification

After processing the connect operation, the Connect use case, call a method in the object explorer:

objectExplorer.Add(theNewConnection);

The Connect use case needs to know too much about the Object Explorer use case, it needs a reference to the object explorer, ergo this is a bad design, because it violates almost any letter in S.O.L.I.D.

Option B: common events

The Connect use case has an event named ConnectionAdded and the Object explorer is subscribed to this event. We are moving the problem to the other side, the Connect use case is agnostic about the Object Explorer but the Object Explorer needs to know about the Connect use case, and this solution has the same problem that the former.

Option C: event publishing

Object explorer is subscribed to an event named ConnectionAdded which is defined as a class.

public class ObjectExplorer{

  public ObjectExplorer(IEventAggregator eventAggregator)
  {
     Connections = new List<Connection>();
     eventAggregator.Subscribe<ConnectionAdded>(AddConnection);
  }
  
  public IEnumerable<Connection> Connections{get; private set;}

  private void AddConnection(ConnectionAdded connectionAdded)
  {
     Connections.Add(connectionAdded.Connection);
  }
}

The Connect use case publish the event when its ready;

public class AddConnectionUseCase{

  private IEventAggregator eventAggregator;

  public AddConnectionUseCase(IEventAggregator eventAggregator)
  {
     this.eventAggregator = eventAggregator
  }
  
  private void Connect()
  {
     //do stuff
     eventAggregator.Publish<ConnectionAdded>(args);
  }
}

This is it. Any part of our system can publish this event, and any part of our system can be subscribed. This architecture is very extensible, flexible, easy to test and easy to maintain.

The concept is very close to Domain Events.

You can read more on Composite Application Guidance, also Ayende Rahien has an artifact in his Effectus application.

In my next post I’ll show you a concrete implementation of IEventAggregator.

| More

5 comentarios:

Jose, one thing regarding this approach...Don't you think using this extensively in a larger systems will result to chaos? I mean, every part of the system could publish a message and every other part could listen, but what happens when you want to find a specific sender/reciever? Same thing happens when using a ServiceBus, or theorethically any pub/sub architecture.

José F. Romaniello dijo...

Two questions:
1-Why or when do you want to find a specific sender or receiver?
2-What is the other way around?

<span>hmmm....let's say, we have a ConnectionAdded event, but there may be a lot of components using this event which may not be easy to find in case of a refactoring or requirement change. I think this architecture is great but add to the complexity of the whole system, specially in larger systems with a lot of event types, publishers and subscribers.</span>

<span>I know where you are going, but the other way of doing things is more chaotic, and add more complexity to the whole system. Coupling is the real problem..</span>

Maybe for larger systems you could create separate event aggregators for each bigger part of this system?

Publicar un comentario en la entrada