Как насчет использования композиции поверх наследования? Реализации start
и process
могут быть предоставлены функциями, как в примере ниже:
import java.util.function.BiFunction;
import java.util.function.Function;
class X<T> {
public String start(BiFunction<String, String, String> f, String s1, String s2) {
return f.apply(s1, s2);
}
public String process(Function<T, String> f, T t) {
return f.apply(t);
}
// example
public static void main(String[] args) {
X<String> xString = new X();
xString.start((s1, s2) -> s1 + s2, "a", "b");
X<Long> xLong = new X();
xLong.process((t) -> { Long tt = t * 2;return tt.toString(); }, 4L);
}
}
То же, что и в предыдущем примере, но с реализациями, предоставленными в конструкторе и использующими функциональные интерфейсы вместо лямбда-выражений.
import java.util.function.BiFunction;
import java.util.function.Function;
class StartFunctionExample implements BiFunction<String, String, String> {
@Override
public String apply(String s1, String s2) {
return s1 + s2;
}
}
class ProcessFunctionExample implements Function<Long, String> {
@Override
public String apply(Long t) {
Long tt = (t * 2);
return tt.toString();
}
}
class Z<T> {
private final BiFunction<String, String, String> startFunction;
private final Function<T, String> processFunction;
public Z(
BiFunction<String, String, String> startFunction,
Function<T, String> processFunction
) {
this.startFunction = startFunction;
this.processFunction = processFunction;
}
public String start(String s1, String s2) {
return startFunction.apply(s1, s2);
}
public String process(T t) {
return processFunction.apply(t);
}
// example
public static void main(String[] args) {
Z<Long> xLong = new Z(new StartFunctionExample(), new ProcessFunctionExample());
xLong.start("a", "b"); // ab
xLong.process(7L); // 14
}
}