Click or drag to resize

Delegates

DME Component Libraries uses a type of object called a Delegate as a conventional way to provide callback objects to certain DME Component Libraries subsystems. In many ways, Delegates are similar to Listener classes from Swing, such as ActionListener, but with several important differences.

Creating and Using Delegates

Delegates are abstract classes that have an abstract invoke() method, which can be of any signature. Each type of delegate defines its own set of parameters and return type. Delegates in DME Component Libraries are implemented as abstract classes (and not simply as interfaces) because they also define equality semantics, via the usual equals() and hashCode() methods.

Let's start with a brief example to demonstrate the concept outside of the DME Component Libraries API.

Java
List<String> strings = Arrays.asList("x", "y", "z", "a");

int matchingIndex = ListHelper.findIndex(strings, new Predicate<String>() {
    @Override
    public boolean invoke(String obj) {
        return "a".equals(obj);
    }
});
// matchingIndex == 3

In this code sample, Predicate is a simple delegate type that defines invoke with the signature:

Java
public abstract boolean invoke(T obj);

and ListHelper.findIndex is a method (defined elsewhere) that simply returns the zero-based index of the first element in a list that matches the provided delegate.

In this example, we construct our particular delegate by creating an anonymous subclass of Predicate, and implementing invoke() as we see fit. You can also define a named subclass if you prefer:

Java
private class ExamplePredicate extends Predicate<String> {
    @Override
    public boolean invoke(String obj) {
        return "a".equals(obj);
    }
}
Java
List<String> strings = Arrays.asList("x", "y", "z", "a");

int matchingIndex = ListHelper.findIndex(strings, new ExamplePredicate());
// matchingIndex == 3

Java 8 adds lambda expressions, which can be used to create delegates more concisely:

Java
int matchingIndex = ListHelper.findIndex(strings, Predicate.of(s -> "a".equals(s)));

Java 8 also provides a method reference syntax, to easily refer to an existing named method with the correct signature:

Java
private boolean examplePredicateMethod(String s) {
    return "a".equals(s);
}
Java
int matchingIndex = ListHelper.findIndex(strings, Predicate.of(this::examplePredicateMethod));

DME Component Libraries uses delegates in a number of places, but the most common is when defining custom evaluators, which is described in more detail in the Evaluators And Evaluator Groups topic. EvaluatorGroup provides several createEvaluator methods, which require you to provide a generic callback delegate which is able to create your custom evaluators when necessary. For example:

Java
public Evaluator<Double> getEvaluator(EvaluatorGroup group, Point point, List<Scalar> scalars) {
    return group.createEvaluator(getEvaluatorCallback);
}

private Evaluator<Double> createEvaluator(EvaluatorGroup group) {
    Evaluator<Double> evaluator = null;

    // in actual code you would construct your custom evaluator here

    return evaluator;
}

private final EvaluatorGroup.Callback0<Evaluator<Double>> getEvaluatorCallback = EvaluatorGroup.Callback0.of(this::createEvaluator);

Note that getEvaluatorCallback, the actual delegate instance, is created only once and stored in a field. This is necessary because EvaluatorGroup uses the equality of the delegate, as well as any other parameters, in order to find and return previously constructed evaluators, and creating and using a new anonymous delegate each time getEvaluator is called would prevent the caching from working properly.