EventBus and Business Logic Decoupling

  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function ereg() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/file.inc on line 647.
  • : Function split() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/modules/filter/filter.module on line 1190.
  • : Function split() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/modules/filter/filter.module on line 1190.
  • : Function split() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/modules/filter/filter.module on line 1190.
  • : Function split() is deprecated in /home/trinitrotoluene/squirvoid.rainpattern.com/modules/filter/filter.module on line 1190.
  • warning: Parameter 1 to theme_tagadelic_display() expected to be a reference, value given in /home/trinitrotoluene/squirvoid.rainpattern.com/sites/default/modules/views/views.module on line 650.
  • warning: Parameter 1 to theme_calendar_display() expected to be a reference, value given in /home/trinitrotoluene/squirvoid.rainpattern.com/includes/theme.inc on line 170.

I didn't think I'd be doing desktop Java any more with the prevalence of rich internet applications (RIA) and my background in Adobe Flex thanks to Thetus. Here I am though realizing that one of the greatest hurdles in medical informatics is the lack of user tools for epidemiologists and public health researchers. So I'm getting into the "swing" of things again and picking up Java Swing and SWT development.

Quite frankly I am surprised by the lack of commonly used, lightweight application frameworks for managing the user interface code. Coming from the perspective of using Flex + PureMVC I expected Java desktop application development to be easily divided up into data model, business logic, styling, and interactive components. All the tutorials and googling I find that there didn't seem to be a common recommendation on how to split up parts of the application to remove coupling.

Though a few libraries exist to provide some design patterns to Swing development, I find EventBus to be pretty slick. It works on the basic publisher-subscriber pattern instead of the listener pattern. The pattern helps to decouple components from one another by having them publish messages that anything can subscribe without adding themselves explicitly to the component broadcasting the event. The API itself is well documented and, using the annotations, very clean to implement. Although I would suggest further decoupling that the examples don't offer. The issue with the examples is that the business logic is coupled with the component. The component is easier to reuse if the logic on handling its outputs and manipulating it are in a controller.

In the example:

public StatusBar extends JLabel {
    public StatusBar() {
        AnnotationProcessor.process(this);
    }
    @EventSubscriber(eventClass=StatusEvent.class)
    public void onEvent(StatusEvent statusEvent) {
        this.setText(statusEvent.getStatusText();
    }
}

The component itself should not subscribe to the event. Suppose you want to use StatusBar in another application that adds additional text to each message. With this code you would have to write a new StatusBar. Instead it would be better to put the logic into a controller, or command class, so that widgets can be reused.

public StatusUpdater {
    private final StatusBar m_statusBar;
    public StatusUpdater(StatusBar statusBar) {
        m_statusBar = statusBar;
    }
    
    @EventSubscriber(eventClass=StatusEvent.class)
    public void onEvent(StatusEvent statusEvent) {
        m_statusBar.setText("Status: " + statusEvent.getStatusText();
    }
}

This would be even better if StatusBar is an interface with a setStatusMessage(String) method so that any implementation can be used. The top-level application controller registers which commands are turned on using AnnotationProcessor.process(Object) which allows us to turn on and off commands. This should help in the creation of a library of reusable interactive widgets. It also carries over into commands, some are canned and ready to use out-of-the-box, while others are application specific but generally they glue together widgets from the library.