Software Mechanics
Why do we even have that lever?

Deconstruction ObjectBuilder - Wiring, part 1

February 11, 2008 17:26 by Chris

I've gotten some feedback that these OB articles are a little long. I'm going to try chopping them up into smaller pieces and see how it goes. Please let me know!

Wiring Objects Together

We've looked at using ObjectBuilder to create objects. But creating an object is only part of the job. Good OO designs use many collaborating objects. Hooking these objects together can take a lot of code, and this wiring code is often hard to maintain. ObjectBuilder can be used to automate this wiring as part of the construction process, or even on objects that already exist.

This kind of wiring is at the core of the Dependency Injection pattern, which we'll get to in just a few more installements.

Wiring Events

As an example of the kinds of object wiring you'd want to automate, I built a simple event broker object. Events are a fundamental part of the .NET object model, and are used throughout the BCL. Events are raised for everything from buttons being clicked to assembly resolution failing. They're a great tool.

But (isn't there always a but?) building event driven systems can be very complex. In order to become an event receiver, your object has to have a reference to the event source. This isn't an issue on a simple dialog box, but in a larger app this can result in spaghetti very quickly. For example, consider implementing the basic cut, copy, and paste operations on a form with a bunch of text boxes and a menu. Each text box would need to hook up to the menu items. But wait - these events also need to hook up to the clipboard keyboard shortcuts. But wait - the keyboard shortcuts are sent to the text boxes themselves, which means that the text boxes actually produce as well as respond to these events. This means (at first glance) that every text box needs to hook up to events on every other text box. Ick.

There's an old adage in computer science: "Every problem can be solved with another layer of indirection." That's what the event broker provides . Instead of registering with every possible producer of an event, you instead register with only one - the broker. The broker takes care of the details of routing events, regardless of how they're generated, to the objects that care about them.

As a side note: This event broker is intended as a demonstration, not as a production tool. For a more industrial strength implementation of this concept, check out the Composite UI Application Block and other parts of the patterns & practices client guidance.

Here's a test that demonstrates the API of the event broker:

1       [TestMethod]
2       public void ShouldCallSubscriberWhenPublisherFiresEvent()
3       {
4           EventBroker broker = new EventBroker();
5           EventSource1 publisher = new EventSource1();
6           string publishedEventName = "MyEvent";
7           bool subscriberFired = false;
8           EventHandler subscriber = delegate { subscriberFired = true;  };
9
10          broker.RegisterPublisher(publishedEventName, publisher, "Event1");
11          broker.RegisterSubscriber(publishedEventName, subscriber);
12
13          publisher.FireEvent1();
14
15          Assert.IsTrue(subscriberFired);
16      }
17
18  class EventSource1
19  {
20      public event EventHandler Event1;
21
22      public void FireEvent1()
23      {
24          OnEvent1(this, EventArgs.Empty);
25      }
26      protected virtual void OnEvent1(object sender, EventArgs e)
27      {
28          if (Event1 != null)
29          {
30              Event1(sender, e);
31          }
32      }
33
34      public int NumberOfEvent1Delegates
35      {
36          get
37          {
38              if( Event1 == null )
39              {
40                  return 0;
41              }
42              return Event1.GetInvocationList().Length;
43          }
44      }
45  }
46

At line 4, we create the broker. We create an object that exposes a .NET event on line 5. The definition of this type starts on line 18. Notice it has a public event of type EventHandler named Event1 (defined on line 20).

Line 10 is where we register the publisher. The parameters are the name that the broker will use to reference this event (MyEvent), the publishing object, and the name of the event field that actually raises this event (Event1). Note that the name the broker uses and the name the publishing type uses can, and often will, be different.

On line 8, we create an EventHandler delegate instance; this is the subscriber. I'm using the C# anonymous delegate syntax here; in a bigger case this would usually be a reference to an event handling method in a subscribing object, but for the simple case here we don't need another object.

Finally, in line 13 we raise publisher.Event1. This causes the event to fire into the broker, and the broker calls the subscribing delegate. Pretty simple to use.

At least, it's simple in this simple scenario. But going back to our clipboard example, we have three events per publisher, and we'll need to have three subscriptions to match. All those calls to RegisterPublisher and RegisterSubscriber are tedious to write and easily gotten wrong. Wouldn't it be great if we could somehow grab and object and just figure out what needs to be registerd and call it automatically?

Next time, we'll configure ObjectBuilder to do exactly that.

Event broker code download:

EventBrokerSample.zip (24.18 kb)


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Comments

Comments are closed