Friday, July 13, 2007

Observer in the Wild

The Design Patterns book study group I participate in met last week and discussed the Observer Pattern for an hour.

The Observer Pattern appears frequently in GUI development, and most people are at least familiar with the Swing style MouseListener interface (or others like it). Basically, a client object declares itself to be an observer (listener) and passes itself off to an observable subject. The subject keeps a list of all observers and notifies them when some event has occurred.

Be cautious in thinking that this is a pattern that needs to be emulated. There are a lot of different ways to implement the Observer Pattern beyond this common method. In fact, as Stuart Halloway recently pointed out, some languages are sufficiently advanced (or just different) to have no need for this pattern at all.

One Java compatible alternative implementation is to not require the observers to declare a specific interface and instead use reflection to notify listeners that an event has occurred. This may sound suspect on the surface… but consider it for a moment. If a method name were invoked reflectively then there is little advantage to not declaring an interface… it just makes the Observer pattern harder to understand and harder to support in an IDE. But if method parameters are analyzed instead, then you get several advantages. One, the Observable object is not coupled to any specific client interface, and any object at all can become an observer of events. Kinda nice. Two, parameters can be analyzed and the most specific method can be called for the event. For instance, if you have a listener of cascading style sheet property events, and want to be notified when a property changes, then you may have a listener of a CSSChangeEvent… or maybe you only want a CSSFontChangeEvent, which is a more specific sub type of the change event. Traditionally, the listener would have to analyze the observable object to see if the event was /really/ want it was interested in or cast the data sent to it to perform the same check. Ugly, but totally acceptable in the Java world because that’s the way it is done. Using the parameter reflection scheme cleans up the code considerably because methods can declare specifically what types of events they are interested in and the Observable object can suppress events that the listener doesn’t care about; all while still being extremely loosely coupled with that listener. Before writing this off as a hare-brained scheme, consider that the Spring framework for .NET uses a very similar mechanism for their observer implementation. The code base I work on has a similar version also. Of course, there are a few problems with this. Method parameters may be ambiguous, and how the “most specific” method is determined must be documented somewhere… AND the programmer must somehow know to read the documentation (yeah, that’ll happen). Also, IDE support for this does not exist and things like Find Usages and automated refactorings won’t work. A final problem has to do with typing. At what point does the observable check to make sure that the listener actually has a method that can be called? The Java world adheres to the fail early/fail fast error handling principle, so the initial inclination would be to check the listener as it is registered to make sure it has an event handler method that can be called. But as Groovy gains usage, it would be possible to register a Java/Groovy object with an Observable that does NOT have valid callback methods and then later dynamically add those methods onto the object as a mixin. Far fetched, I know, but technically possible. An open discussion point from the meeting is whether or not this parameter reflection theme constitutes “Duck Typing“, but I’ll leave that for the comments section below.

A second alternative that is not Java compatible is to use closures. But when Java 7 is released it just may be part of the language! In many languages, a method is a first class citizen of the object world: it can be passed as a parameter, returned from a function, declared as a variable, and stored as an item’s state. C++, SmallTalk, JavaScript, Ruby, and Groovy all have some construct like this (plus many other’s, I’m sure). ActionScript 1.2 in Flash performed all of their event listeners like this. The variation here is that instead of creating a small, anonymous class to be a listener, you simply create a small, anonymous method.

Your code goes from:

component.addCSSChangeListener(new CSSChangeListener(){
  onFontChange(){System.out.println("font changed");}
});

to something like:

component.addCSSChangeListener({
  System.out.println("font changed");
});

Closures open up a whole lot of new programming techniques. It is a big change that may or may not be added to the language. If it does, a lot of the interface based programming that we do can be streamlined to be closure/method based. Of course, you can write FORTRAN code in any language you want, and you will always be free to use obsolete constructs with languages that don’t require them. For instance, I googled “Ruby + Observer” and found quite a few examples showing how to implement an interface based observer pattern in Ruby code. I’m sure there is a time and place where that is needed, but a language that provides closures should obsolete this pattern.

A final option, that even less languages support, is to handle observers using pattern matching functions. Some languages support what is called Pattern Matching in method parameters... so dynamic dispatch doesn’t occur simply on the object type, but based on the value of the object too. For instance, consider the following if statement:

void foo(int x) {
  if (x == 0) {
    print("zero");
  } else if (x == 1) {
    print "one");
  } else
    print(x);
  }
}

In a pattern matching language you could instead write it like this:

void foo(0) {
  print("zero");
}
void foo(1) {
  print("one");
}
void foo(int x) {
  print(x);
}

This means that you could declare your listener object to have the method expected, and have the events it wants to handle in the parameters of that method. No if statements, no casts, and no inspecting the Observable to see what event was generated. This has all the advantages to the first option discussed (reflection based on parameters) except that the language supports it instead of having to use reflection and then defining your own parameter precedence level. Also, dynamic dispatch isn’t based on solely object type, but the values of that type as well. So, using the previous CSS handler example, you could have one method that handles changes to the “Tahoma” font, one method that handles changes to any font, and one default method to handle everything else. Ultimate flexibility, and the Observerable is still loosely coupled to the observer because there isn’t even an interface declared that it is dependent on (assuming a weak type system). This is the language feature I want!

So, Java programmers (that’s you), which of these observer patterns is the most awful? Which one would have you cursing the original developer when you’re trying to maintain the code years later? Feel free to let loose...

No comments: