У меня есть вещи (скажем, для контекста, числа), которые могут выполнять операции по своему типу:
interface Number<N> {
N add(N to);
}
class Int implements Number<Int> {
Int add(Int to) {...}
}
и актеров, которые действуют на все подтипы определенной верхней границы:
interface Actor<U> {
<E extends U> E act(Iterable<? extends E> items);
}
Я хочу сделать актера, который действует полиморфно на любой числовой тип:
class Sum implements Actor<Number> {
<N extends Number<N>> N act(Iterable<? extends N> items) {...}
}
Теперь, очевидно, это не работает, потому что Number
и Number<N>
не совпадают. Фактически, поскольку Number
не ограничивает параметр типа конструктора как своего собственного типа, такой актер не может работать. Но я вообще не хочу работать с Number
в целом - я доволен своей функциональностью работать только на Numbers некоторого типа N extends Number<N>
В качестве альтернативы я могу объявить:
interface Actor<E> {
E act(Iterable<? extends E> items);
}
class Sum<N extends Number<N>> implements Actor<N> {
N act(Iterable<? extends N> items) {...}
}
Но это не работает для меня, потому что он заставляет меня знать N
, когда я создаю свой Sum
, который мне не подходит. Это также приводит к уродливому <N extends Number<N>>
для каждого класса или метода, который полиморфно использует a Sum
, вызывая пролиферацию типа беспорядка.
Есть ли какой-нибудь элегантный способ сделать то, что я хочу?
Пример:
Вот пример кода, выражающий то, что я хотел бы сделать.
interface Folder<U> {
<E extends U> E fold(Iterable<? extends E> items);
}
class Sum implements Folder<Number> {
<N extends Number<N>> N fold(Iterable<? extends N> items) {
Iterator<? extends N> iter = items.iterator();
N item = iter.next();
while (iter.hasNext())
item = item.add(iter.next());
return item;
}
}
class Concat implements Folder<String> {
<S extends String> fold(Iterable<? extends S> items) {
StringBuilder concatenation = new StringBuilder();
for (S item : items)
concatenation.append(item);
return concatenation.toString();
}
}
class FoldUtils {
static <U, E extends U> E foldDeep(Folder<U> folder, Iterable<? extends Iterable<? extends E>> itemses) {
Collection<E> partialResults = new ArrayList<E>();
for (Iterable<? extends E> items : itemses)
partialResults.add(folder.fold(items));
return folder.fold(partialResults);
}
}