Я использую внешнюю библиотеку, которая предоставляет тесно связанные классы (сгенерированные из некоторого шаблона), но, к сожалению, без общего интерфейса, например,
public class A {
public UUID id();
public Long version();
public String foo();
public String bar();
}
public class B {
public UUID id();
public Long version();
public String foo();
public String bar();
}
public class C {
public UUID id();
public Long version();
public String foo();
public String bar();
}
// ... and more: D, E, F, etc.
Учитывая, что я не имею никакого влияния на внешнюю библиотеку, каков идиоматический способ написания логики, общей для группы классов, имеющих общие сигнатуры методов (по крайней мере, для методов, используемых общей логикой)?
В настоящее время я делаю один изтри вещи, в каждом конкретном случае:
Я пишу вспомогательные методы, которые получают примитивные результаты от каждого объекта, например,
private static void myHelper(UUID id, Long version, String foo, String bar) {
...
}
Таким образом, я могу "распаковать" объект независимо от его типа:
myHelper(whatever.id(), whatever.version(), whatever.foo(), whatever.bar());
Но это может стать очень многословным, особенно когда мне нужно работать со многими членами.
В сценарии, где я работаю только с геттерами ( т.е. требуется только доступ к текущим значениям объектов), я нашел способ использовать библиотеки отображения, такие как Dozer или ModelMapper, длясопоставить A или B или C смой собственный общий класс, например
public class CommonABC {
UUID id;
Long version;
String foo;
String bar;
}
Играя с конфигурацией, вы можете получить эти библиотеки для отображения всех членов, будь то метод или поле, открытый или закрытый, для вашего класса, например
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);
Но это был своего рода подход с широким мечом, взлом, который IMO явно не оправдал просто для того, чтобы исключить дублирующийся код.
Наконец, в некоторых других сценариях было наиболее кратким просто сделать
private static void myHelper(Object extLibEntity) {
if (extLibEntity instanceof A) {
...
} else if (extLibEntity instanceof B) {
...
} else if (extLibEntity instanceof C) {
...
} else {
throw new RuntimeException(...);
}
}
Очевидно, почему это плохо.
В корпоративных ситуациях, когда выЯ должен жить с библиотекой, которая именно таким образом, что бы вы сделали?
Я склоняюсь к написанию очень явного, если многословно, маппера (не использующего универсальную библиотеку мапперов), который переводит эти сущности изНачните.Но мне интересно, есть ли лучший способ.(Например, есть ли способ «привести» объект к реализации нового интерфейса во время выполнения?)