#java #design-patterns #method-reference #functional-interface
#java #шаблоны проектирования #метод-ссылка #функциональный интерфейс
Вопрос:
Я создаю библиотечный пакет, который имеет интерфейс PropTransformer
, который будет реализован более чем 30 классами. Я беру один такой класс здесь, скажем 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
}
}
Очевидно, что методы классов этой библиотеки могут быть вызваны с помощью new
operator, но поскольку на стороне пользователя может быть выполнено множество преобразований, многие экземпляры будут казаться раздутыми. Что-то вроде:
new ShapeTransformer().transform(...);
new TemperatureTransformer().transform(...);
...
Я мог бы подумать о создании служебного класса Transformer
, который обеспечивал бы прямой вызов для transformers, например
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);
}
}
Пользователь библиотеки может затем использовать его как
Transformer.shapeTransform(...)
Проблемы с этим подходом:
- Он не будет масштабироваться, поскольку класс Transformer будет продолжать расти с увеличением числа реализуемых transformer
PropTransformer
. - Своего рода повторная работа выполняется путем добавления статических методов и переменных в
Transformer
класс
Есть ли более чистый / лучший способ добиться этого? По возможности, через ссылки на методы и / или функциональный интерфейс?
Что-то вроде
Transformer t = new Transformer();
t.transform(ShapeTransformer::transform);
t.transform(TemperatureTransformer::transform);
(^ это просто для того, чтобы дать представление о том, что я ищу. Я не обязательно предлагаю сделать метод transformers статичным)
Комментарии:
1. Может ли клиентский код свободно использовать любую из
PropTransformer
реализаций или это зависит от какого-либо атрибута?2. @Smile Все реализации независимы друг от друга. Клиент свободен и может использовать любое количество реализаций. Единственная причина, по которой реализации реализуют один и тот же интерфейс, заключается в поддержании контракта на роль преобразователя. Отвечает ли это на ваш вопрос?
Ответ №1:
PropTransformer
не является функциональным интерфейсом, поскольку содержит более 1 абстрактного метода. Итак, вы не можете реализовать и вызвать эти методы, используя выражение lamda.
Вы можете разделить PropTransformer
на функциональные интерфейсы PropTransformer
и PropReverseTransformer.
, но решение должно основываться на том, как PropTransformer
вписаться в общий дизайн.
Чтобы еще больше сократить количество шаблонного кода на стороне клиента, вы можете создать PropTransformerFactory
— утилиту для создания PropTransformer
реализаций. Псевдокод:
public class PropTransformerFactory {
public static PropTransformer createShapeTransformer() {
return new ShapeTransformer();
}
public static PropTransformer createTemperatureTransformer() {
return new TemperatureTransformer();
}
}