Saturday, October 16, 2010

Scala exercise 3: decorator and composite design patterns

Introduction

This is the third exercise in my Scala exercises series. If you haven’t seen it before, you may want to start from exercise 1: template method and exercise 2: observer design pattern. Below is exercise 3: decorator and composite design patterns.Problem: In most UI frameworks including JSF, Wicket or Swing, you will need to provide a callback/listener object to handle requests from the user. Typically in such a callback, if there are some errors, you'd like to display a specific error message instead of propagating it to the framework, otherwise the framework would simply display a generic error to the user.To hand code such a callback, you may do it like:

The problem with this approach is that there is a lot of boilerplate code there, while most usually we only want to say for exception class E1, display some error message M1:

new ErrorHandlingCallback( //classOf[Foo] is the same as Foo.class in Java classOf[LoginException], "failed to login", classOf[SQLException], "...") { def performBusinessLogic(ev: Any) { //perform the business logic here }}

But what if you'd like to extract some information from the exception and include it into the error message or would like to do something special? Then, ideally, you should be able to specify a function as the error handler:

Finally, you should be able to pre-define an object to handle the commonly seen exceptions:

//ideally you should be able to "add" the error //handlers together to get a compound error//handlerval defaultErrorHandler = (classOf[IOException], "I/O error") + (classOf[Exception], "Unknown catch all error")

//implicit conversion methods must always be inside an object//but not a class, so that the client can static-import the//object's methods.object ErrorHandlerUtil { //allow you to use a function as an error handler implicit def fromFunc(f: Exception => Boolean): ErrorHandler = new ErrorHandler() { def handle(e: Exception) = f(e) } //allow you to use a pair (error class, error message) as an error reporter implicit def fromPair(p: (Class[_ <: Exception], String)): ErrorHandler = //use _1 and _2 to access the elements of a pair (tuple) new ClassBasedErrorReporter(p._1, p._2)}

abstract class ErrorHandlingCallback(errorHandler: ErrorHandler) extends Callback { //overload the constructor to take multiple error handlers (the star does that) def this(errorHandlers: ErrorHandler*) = //the anonymous function _+_ is the same as (x, y) => x+y as each argument //only appears once in the body. Note that you have defined a method //named + above to combine two error handlers together. this (errorHandlers.reduceLeft(_ + _))