Wednesday, November 9, 2011

Transformation Channel pattern for Scala

I'm particularly keen in Scala because of my strong integration background. Scala (and functional programming in general) promotes message-based communication between the objects. When we design the applications to be more message-oriented, we also could start using patterns typical for integration architecture (like Hohpe's EIP patterns).

One of the most powerful integration pattern is Message Translation (aka Message Transformation). The idea behind this pattern is quite simple. You intercept the message and affect it in some way.



How this pattern can apply to the Object Oriented design? Imagine that you want to pass some data from one object (let's call it Data Provider) to the another that will perform some operation on the data (we will refer the second object as Data Receiver). Then Data Receiver processes the data and returns it.



We may also want Data Receiver to send processed data to some other object.



The processing scheme presented above is quite common. The idea behind Message Transformation pattern in the context of Object Oriented design is to allow us to intercept the latter processing scheme in order to affect the message sent between Data Provider and Data Receiver.

To achieve the goal described above, we need to add a layer of abstraction between the communication objects. Let's name it TransformationChannel. Instead of sending messages directly to Data Receiver, Data Provider will send messages to the channel. Than channel will notify the Data Receiver that message with data is available to be processed.



Channel allows us to register message translators to listen for the data and modify it before Data Receiver gets it.



Using the Message Translator pattern and Transformation Channel we can easily add additional behavior to the default version of the algorithm processing our data.

I've created a simple implementation of the Transformation Channel in Scala. It uses partial functions and pattern patching as Message Translators. In the example below Strings sent to the Transformation Channel are converted to uppercase by Data Receiver. This base functionality can be packed into the jar file and delivered to the other team of developers.

// Some data to process
val data = "foo"

// Data Receiver which converts Strings to upper case
val dataReceiver: PartialFunction[Object, String] = {
  case s: String => s.toUpperCase
}

// Transformation channel with registered Data Receiver 
val channel = new TransformationChannel(dataReceiver)

// Data processing
val upperCasedData: String = channel.transform(data)


If at some point the other team of developers decides that data should be affected somehow before the processing, they can dynamically add Message Translator (defined as partial function) to the channel defined by us.

// Register Message Translator
channel.addPreTransformation {
   case s: String => "prefix_" + s
 }

// Process data
val prefixedAndUpperCasedData: String = channel.transform(data)
When would you like to use Transformation Channel?
  • when you want to deliver default implementation of data exchange between two objects but still be able to dynamically modify or extend this behavior
  • when you can't predict all possible scenarios of data exchange between two objects
  • when data exchanged between two object is likely to be modified by other collabolators
  • when you want to provide plug-in point for communication between two objects
  • when you want to provide unifed implementation of the Observer design pattern
  • when you want achieve very loose coupling between two communicating objects

1 comment:

  1. Does anybody know how to find the exact value of the intercepts of two lines in excel chart. I can find the aprox. value but i need an exact one. I use office 97 ( i work for a not very technologically advanced company)...

    I would appreciate any help.

    ReplyDelete