This became a longer reply than I intended. Tl;dr -summary at the bottom.
In a way, you are right. There is a one-to-one relationship on who listens on what kinds of events, indeed. However, this isn’t restricted to instantiable classes, but can be applied also to abstract classes and, as
the wiki
encourages, interfaces (as shown in the
unit tests
). This is kind of a “works as intended” -situation. The thought behind this is that this kind of enourages/forces you to write clear and descriptive interfaces, allowing you to use the “type hierarchy” feature in IDEs to find out all listeners for an event. Also, the register()-method is designed to be called in the same class where the Blackboard instance is stored.
This would lead to the intended use pattern: “register()”-calls are all bunched up somewhere near the “new Blackboard()” call, while each implementer of Listener subinterfaces calls the “getBlackboardFromSomewhere().addListener(this, MyEventListener.class)” on their own.
I happened to notice that my
example application
doesn’t reflect this at all, and I’m sorry about this. It is currently done the quick’n’dirty way, which is explicitly discouraged by the wiki. I should fix the example asap.
Now, the question remains, are these good design decisions. Maybe, maybe not. It has thus far worked well in a somewhat complex project, but it does accumulate a lot of interfaces and classes. But I have already thought of some design changed: Removing the Notifier interface, since it’s essentially dead weight and doesn’t bring any added value to the table. I have also thought of disallowing the registering of classes, and only allow interfaces (not sure what to do with abstract classes).
Your suggestion has given me something to think about, for sure. The more I look at it, the more I’m starting to like it. Your approach might do away with the Listener-interface, too, since the value would be in the annotations, and the interface would give no guarantees of anything. Who listeners to what can still be inspected by the IDE, since you can check for references to the Event classes instead.
The two downsides I need to think about are that it would break the current API pretty badly and you would lose the requirement of properly done interfaces, which you could call manually on demand. Neither seem all that problematic, though, since the API doens’t have all that much of a circulation yet (~50 downloads), and Blackboard should not be used for close proximity message passing, but for more of a broadcasting kind-of-thing.
tl;dr: I might need to rethink some things, and the example application needs to be fixed anyways.