Могу ли я передать сложную структуру типов в Java-дженериках?
В настоящее время я пытаюсь реализовать API для концептуальной модели с использованием интерфейсов Java и дженериков. Модель (Transmodel V5.0) подробно описывается как модель отношения сущности, но она не указывает некоторые используемые базовые типы. Например, типы идентификаторов для разных объектов или типы, используемые для установления порядка в последовательностях, не определены.
Поскольку я хочу, чтобы API как можно более общий, я начал использовать generics для настройки этих деталей. Я не хочу делать какие-либо предположения о типах, в том числе не предполагая, что что-либо согласовано. Каждый объект может иметь различный тип идентификатора, каждая последовательность может иметь другой тип, используемый для целей заказа.
Проблема, с которой я сталкиваюсь, заключается в том, что сложность растет быстрее, когда один объект ссылается на другой - мне не только нужно передавать типы для его идентификатора, но и все, что необходимо для настройки ссылочного объекта.
Например, у меня есть:
/**
* @param <ID> The type for the identifier of this entity.
* @param <ID_JP> The type identifying journey patterns.
* @param <OP_JP> The ordering used for points in journey patterns.
* @param <JP> The type of journey pattern referenced by this entity.
*/
public interface VehicleJourney<
ID,
ID_JP, OP_JP extends Comparable<OP_JP>, JP extends JourneyPattern<ID_JP, OP_JP>
> extends IdentifiableObject<ID>
{
JP getJourneyPattern();
}
Я все еще могу прочитать это и понять, но он становится более чем многословным. И тогда такие объекты, как VehicleJourney, могут ссылаться на другие объекты, что приводит к взрыву списка параметров типа. Это почти самый маленький нетривиальный пример, о котором я могу думать.
Есть ли способ создать единый объект Java, который моделирует всю конфигурацию системы типов? Я думаю о том, что будет иметь все типы идентификаторов и типы упорядочения, и затем может быть передан как один, превратив пример выше в нечто вроде этого:
public interface VehicleJourney<CONF, JP extends JourneyPattern<CONF>>
extends IdentifiableObject<???>
{
JP getJourneyPattern();
}
В месте с вопросительными знаками тип идентификатора VehicleJourney должен каким-то образом быть извлечен из CONF. Если это будет осуществимо, то сложность должна оставаться на управляемом уровне.
Ответы
Ответ 1
Не будет красивым.
Вы можете использовать unanchored типы и упростить, имея тип, который группирует типы id и compator:
public interface Meta<ID, COMP extends Comparable<COMP>> {
}
public interface IdentifiableObject<M extends Meta<?, ?>> {
}
public interface JourneyPattern<M extends Meta<?, ?>>
extends IdentifiableObject<M> {
}
public interface VehicleJourney<M extends Meta<?, ?>, JP extends JourneyPattern<?>>
extends IdentifiableObject<M> {
}
Вам действительно не нужно указывать имена для привязки вложенных типов типов. Когда у вас есть конкретный класс (или даже суб-интерфейсы), все типы будут привязаны в любом случае. Например:
public class VehicleJourneyImplMeta implements Meta<String, String> {
}
public class VehicleJourneyImpl extends IdentifiableObjectBase<VehicleJourneyImplMeta>
implements VehicleJourney<
VehicleJourneyImplMeta,
JourneyPattern<Meta<Integer, String>>> {
}
Вам нужно будет делегировать доступ к типам в Meta, используя промежуточные классы, наиболее вероятно анонимные:
VehicleJourney<Meta<String, String>, ?> v = something();
Meta<String, String> m = v.getObjectMeta();
String idOfV = m.getId();
С помощью различных параметров типа на уровне метода вы, вероятно, можете сделать эту работу.
Мне кажется, что вы (и я, и большинство людей) действительно хотите что-то вроде этого:
public interface VehicleJourney<M extends Meta<?, ?>, JP extends JourneyPattern<?>>
extends IdentifiableObject<M> {
public JP.M.ID getIdOfReferencedX();
}
К сожалению, Java не поддерживает типизацию JP.M.ID
как возвращаемого типа. Возможно, кто-то поднимет JSR для этого. Байт-код содержит имена параметров типового типа, если я правильно помню.