AutoGen: Extending the Convention Approach to Event Wiring

I couldn’t quite leave this code alone.  I have to admit, the whole reason I wrote the AutoGen stuff in the first place was out of frustration at the amount of plumbing factories I was having to write in a recent project.  Well, the plumbing of event wiring was getting at me as well, so I decided to do something about that as well.

Let me explain the problem I wanted to solve, first.  I recently had to modify a program that took one fix connection to handle one or two, depending on the deployment scenario.  Now, obviously, handling forty is pretty much like handling two from an API perspective, but going from one to two tends to involve refactoring.  The annoyance was, in this particular case, it was absolutely obvious what I wanted to do.  I wanted both to open, close and reset at the same time.  This was done through the obvious interface.

interface IFixConnection {
    void Open();
    void Close();
    void Reset();
}

Now, here, there’s no complex API.  It’s just a series of commands.  All I want is for it to pass the commands on to the implementors of the interface.  So, I wanted to be able to write.

container.Register(Component.For<IFixConnection>().Named("AggregateConnection").AutoWire("principalConnection", "controlConnection"));

and for it to “just work”.  Actually, I wanted to go further than that.  Large parts of my system need to know when a reset occurs, but I didn’t have to have to wire them up by hand.  So actually the interface looked like this:

internal interface IResettable {
    void Reset();
}
interface IFixConnection2 : IResettable {
    void Open();
    void Close();
}

Where quite a lot of objects implemented IResettable.  Now, I wanted the following:

  • The controller object shouldn’t need to know that some people only implemented part of the interface.
  • I shouldn’t have to wire up the objects to the AutoWire aggregate by hand.
  • It should keep track of creation and release.

So, I added in the following syntax:

container.Register(Component.For<IFixConnection2>().Named("AggregateConnection").AutoWire(s => s.WithCurrentObjects().UseWeakReferences()));

This supports the above behaviour.  It also has the advantage of requiring the minimum rewiring for different deployment scenarios.  The linkage works on the basis of whether or not the interface is implemented, not whether it is exposed.  This is a deliberate design decision to sacrifice a small amount of control for ease of use.  It certainly didn’t simplify the implementation.  Finally, the aggregate object exposes an IBroadcaster interface, defined as follows:

public interface IBroadcaster {
    void Add(object listener);
    bool Remove(object listener);
    void Clear();
    IEnumerable<object> GetListeners();
}

which can be used to dynamically modify the list at run-time.  It also implements a chain of responsibility pattern if the target interface method returns bool or a class.  Finally, it’s worth noting that the AutoWire does the opposite of AutoGen when presented with a Dispose method.  A dispose method clears the listeners, it doesn’t dispose of the listeners.  This is a special rule, but I think a useful one.  Anyone who really did want to dispose of the listeners can always get the list through GetListeners.

Anyway, it’s on the patch list in donjon.

Technorati Tags: ,

Published by

Julian Birch

Full time dad, does a bit of coding on the side.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s