FunctionMap is a handy class that allows a set of object transformations to be mapped at run time without having to define a bunch of extra interfaces and without having to evaluate the transformations at the time the mapping is created. Suppose we have an object:
class NumberPair { double a; double b; }
and we want to define two transformations of the object, “multiplication” and “addition,” and be able to map these transformations to a set of keys. Normally we’d have to define two classes and a common interface:
abstract class NumberPairTransformation { protected NumberPair numberPair; NumberPairTransformation(NumberPair numberPair) { this.numberPair = numberPair; } abstract double getValue(); } class Multiplication extends NumberPairTransformation { double getValue() { return numberPair.a*numberPair.b; } } class Addition extends NumberPairTransformation { double getValue() { return numberPair.a+numberPair.b; } }
and create a map
static Map<String,Double> getNumberPairMapping(NumberPair numberPair) { Map<String,Double> map = newHashMap(); map.put("multiplication", new Multiplication(numberPair).getValue()); map.put("addition", new Addition(numberPair).getValue()); return map; }
with a FunctionMap we can do the same thing with:
static Map<String,Double> getNumberPairMappingBetter(NumberPair numberPair) { return FunctionMapFactory.<NumberPair,String,Double>factory() .withMappedObject(numberPair) .withMapping("multiplication", new Function<NumberPair,Double>() { public Double apply(NumberPair numberPair) { return numberPair.a*numberPair.b; } }) .withMapping("addition", new Function<NumberPair,Double>() { public Double apply(NumberPair numberPair) { return numberPair.a+numberPair.b; } }) .build(); }
There is a slight difference in the way these two maps will behave: getNumberPairMapping() returns a Map<string,Double> whose Double values have already been computed. The values of the map from getNumberPairMappingBetter() are not calculated until Map.get() is called. To achieve the same thing with our NumberPairView interface, we’d have to return a Map<string,NumberPairView> and then call getValue() on the entries, which is of course far less generic and useful since we now have to deal with NumberPairViews instead of Doubles.
FunctionMap can be useful in situations where it is better to shift the computational work of creating a map of values from the builder to the consumer, for example when the consumer will only be using a subset of the values in the map, and it would be messy or impossible to add new interfaces. It also provides a compact way to define a set of mappings where creating an interface would result in a class consisting solely of getXYZ() methods. An example of this would be parsing fixed-field messages where a pre-defined byte range maps to a specific named value.
What follows is the code for FunctionMap and FunctionMapFactory. Hopefully you will find them useful!