A real-life example
Whenever I need to explain the benefits of event-driven design to somebody, I tend to use the same example, which I'll be also using here in this documentation.
A typical use case
Imagine, you have an authentication mechanism in your application, which could be implemented like this:
public class Auth { private String username; public boolean authenticate(String username, String passwd) { if (username.equals("schst") && passwd.equals("secret")) { this.username = username; return true; } return false; } public String getUsername() { return this.username; } public void clearAuthentication() { this.username = null; } }
OK, this is probably not something you will be using in a real-life application, as this is extremely simplyfied.
Now you want to display the user a login page in the application and write a logfile if somebody successfully logged in and another logfile, if the authentication failed:
Auth user = new Auth(); if (user.authenticate(username, password) == true) { // User successfully logged in // place the logging code here logger.writeLog(....); } else { // login failed // place the logging code here logger.writeLog(....); }
Although this code will work, it can be greatly improved using a more flexible approach and the EventDispatcher package:
import net.schst.EventDispatcher.*; EventDispatcher disp = EventDispatcher.getInstance(); Auth user = new Auth(); if (user.authenticate(username, password) == true) { // User successfully logged in disp.triggerEvent("onLogin", user); } else { // login failed disp.triggerEvent("onLoginFailure", user); }
Instead of writing any logfiles you are just triggering new events. To actually write the logfiles, you need to register event listeners prior to launching your application.
import net.schst.EventDispatcher.*; public class AuthLogger implements EventListener { public void handleEvent(Event e) { String eventName = e.getName(); String username = e.getContext().getUsername(); // now place the logging code here... } } EventListener log = new AuthLogger(); EventDispatcher disp = EventDispatcher.getInstance(); disp.addEventListener("onLogin", log); disp.addEventListener("onLoginFailure", log);
This way, you've achieved a clean separation of the logging code from the business logic. At a first glance, it seems a lot more complicated, than just checking the return value of authenticate() and then writing a logfile, but this approach has several benefits:
- remove all logging functionality, by just removing the addEventListener() calls
- add logging to any other event (e.g. onLogout) by just adding the event listener to this event
- change the logging code to anything else (e.g. sending mails) without touching the business logic.
The following pages will show you how to add more features and even achieve interaction between the event listeners and your application. So how about a pluggable blacklist-check?
