У меня довольно сложный набор универсальных классов в Java. Например, у меня есть интерфейс
interface Doable<X,Y> {
X doIt(Y y);
}
и реализация
class DoableImpl implements Doable<Foo<Bar<Baz,Qux>>,Foo<Bar<Zot,Qux>>> {
Foo<Bar<Baz,Qux>> doIt(Foo<Bar<Zot,Qux>> fooBZQ) { ... }
}
В реальной реализации Doable
имеет довольно много методов, и поэтому Foo<Bar<Baz,Qux>>
и т. Д. Появляются снова и снова.
(Хотите верьте, хотите нет, но универсальные типы немного более болезненны, чем эта. Я упростил их для примера.)
Я бы хотел упростить это, избавить себя от необходимости печатать и облегчить нагрузку на глаза. Я хотел бы иметь простой «псевдоним типа» для Foo<Bar<Baz,Qux>>
и т. Д., Скажем FooBBQ
и FooBZQ
.
Моя текущая идея - определить классы-оболочки:
class FooBBQ {
public static FooBBQ valueOf(Foo<Bar<Baz,Qux>> fooBBQ) {
return new FooBBQ(fooBBQ);
}
private Foo<Bar<Baz,Qux>> fooBBQ;
private FooBBQ(Foo<Bar<Baz,Qux>> fooBBQ) {
this.fooBBQ = fooBBQ;
}
public Foo<Bar<Baz,Qux>> toGeneric() {
return fooBBQ;
}
}
class FooBZQ { /* pretty much the same... */ }
class DoableImpl implements Doable<FooBBQ,FooBZQ> {
FooBBQ doIt(FooBZQ fooBZQ) { ... }
}
Это хорошо работает, но имеет несколько недостатков:
- Нам нужно определить отдельные оболочки для каждого общего экземпляра. Классы-обертки короткие и стилизованные, но я не могу придумать, как их макросить.
У нас есть накладные расходы на перевод (концептуально, если не оперативно) вызова valueOf
и toGeneric
для преобразования между FooBBQ
и Foo<Bar<Baz,Qux>>
. Например, если doIt
вызывает какую-то библиотечную подпрограмму, которая ожидает Foo<Bar<Zot,Qux>>
(что делает реальная реализация), мы в итоге получим что-то вроде
return FooBBQ.valueOf( libraryCall( fooBZQ.toGeneric() ) )
где бы мы изначально имели
return libraryCall(fooBZQ);
Есть ли другой способ получить поведение "псевдоним типа", которое я хочу здесь? Возможно, с помощью какого-нибудь стороннего макро-инструментария? Или я должен признать, что мне придется много печатать, одним способом (используя универсальные типы в реализации) или другим (писать обертки для них)? Может быть, иметь столько общих параметров, это просто плохая идея, и мне нужно переосмыслить проблему?
[ОБНОВЛЕНИЕ] ОК, я запрещаю дальнейшие ответы "не делай этого". Примите это как данность, что Foo<Bar<Baz,Qux>>
имеет подлинное значение в моей проблемной области (Пит Киркхэм может быть прав, что у него достаточно значения, чтобы получить правильный класс-обертку с описательным именем). Но это проблема программирования; не пытайтесь определить проблему.