Search code examples
javadesign-patternsmethod-referencefunctional-interface

What's the best way to provide interface to these library functions?


I'm building a library package, which has an interface PropTransformer which will be implemented by 30+ classes. I'm taking one such class here say ShapeTransformer

public interface PropTransformer<T, R> {
    R transform(T t);
    T reverseTransform(R r);
}
public class ShapeTransformer implements PropTransformer<List<String>, Set<String>> {
    
    @Override
    public Set<String> transform(final List<String> list) {
        // transform code
    }

    @Override
    public List<String> reverseTransform(final Set<String> set) {
        // reverseTransform code
    }
}

This library's classes methods can be invoked using new operator obviously, but since a lot of transformations can be done on user side so a lot of instantiation will appear bloated. Something like:

new ShapeTransformer().transform(...); 
new TemperatureTransformer().transform(...);
...

I could think of creating a utility class Transformer which would provide a direct invocation for transformers, like

public class Transformer<T, R> {

    private static ShapeTransformer shapeTransformer = new CompatibleDevicesTransformer();

    public static Set<String> shapeTransform(final List<String> list) {
        return shapeTransformer.transform(list);
    }

    public static List<String> shapeReverseTransform(final Set<String> set) {
        return shapeTransformer.reverseTransform(set);
    }
}

Library user can then use it like

Transformer.shapeTransform(...)

Problems with this approach:

  • It won't scale as Transformer class will keep growing with number of transformers that implement PropTransformer.
  • Kind of repeat work is being done by adding static methods and variables in Transformer class

Is there a cleaner/better way to accomplish this? Through method reference(s) and/or functional interface(s), if possible?

Something like

Transformer t = new Transformer();
t.transform(ShapeTransformer::transform);
t.transform(TemperatureTransformer::transform);

(^ this is just to provide a peek into what I'm looking for. I'm not necessarily suggesting to make the transformers method static)


Solution

  • PropTransformer is not a functional interface as it contains more than 1 abstract method. So, you can't implement and call these methods using lamda expression.

    You can split PropTransformer into functional interfaces PropTransformer and PropReverseTransformer. But decision should be based on how PropTransformer fit into overall design.

    To further reduce boilerplate code at client side, you can create PropTransformerFactory - a utility to create PropTransformer implementations. Pseudo Code:

    public class PropTransformerFactory {
        public static PropTransformer createShapeTransformer() {
            return new ShapeTransformer();
        }
    
        public static PropTransformer createTemperatureTransformer() {
            return new TemperatureTransformer();
        }
    }