Я объясню свой вопрос на примере.
У меня есть два класса NumberGeneratorApple
и NumberGeneratorOrange
.Оба они имеют метод с одинаковой сигнатурой и типом возврата public Integer getNumber()
.Проблема в том, что они не реализуют один и тот же интерфейс, хотя это было бы логично.Я мог бы создать интерфейс с этим методом и изменить эти классы для его реализации, но я не хочу этого делать.Вот почему.Эти классы генерируются автоматически, скажем, из xml.В реальном примере есть десятки таких классов.Мы должны генерировать их время от времени, и это перезаписывает старые.Я не хочу менять каждый класс вручную, чтобы реализовать интерфейс после каждого поколения.Также может быть неочевидным, что это должно быть сделано для какого-то другого человека, работающего над тем же проектом, и даже для меня через некоторое время.
Вот первый класс:
public class NumberGeneratorApple {
public Integer getNumber(){
return 9;
}
}
и второй:
public class NumberGeneratorOrange {
public Integer getNumber(){
return 19;
}
}
Хотя они не реализуют один и тот же интерфейс, мне нужно использовать их в общем виде.Я просто хочу сделать что-то вроде этого:
public class ClassThatOperates<T extends NumberGeneratorInterface> {
T generator;
public ClassThatOperates(T generator) {
this.generator = generator;
}
public void doSomeOperation(){
//Obviously it won't work for NumberGeneratorApple and NumberGeneratorOrange
// because they do not implement NumberGeneratorInterface
//And if I change "<T extends NumberGeneratorInterface>" to "<T>"
// I cannot write method call "generator.getNumber()"
System.out.print("The number with constant is: ");
System.out.println(generator.getNumber() + 5);
}
}
Это интерфейс (я знаю, что public там не нужен, и он есть по умолчанию. Я просто хочу подчеркнуть это):
public interface NumberGeneratorInterface {
public Integer getNumber();
}
Как видите, это невозможно сделать, потому что ни NumberGeneratorApple
, ни NumberGeneratorOrange
не реализуют NumberGeneratorInterface
.Однако я нашел какое-то решение, но, следуя своему инстинкту, я думаю, что оно довольно плохое.Я сделал классы-оболочки:
public class NumberGeneratorAppleWrapper extends NumberGeneratorApple implements NumberGeneratorInterface {
}
и
public class NumberGeneratorOrangeWrapper extends NumberGeneratorOrange implements NumberGeneratorInterface {
}
Это немного сложно.Сначала это может быть неочевидно, но когда вы вызываете getNumber () для объекта одного из этих классов, вы на самом деле вызываете что-то вроде этого:
@Override
public Integer getNumber() {
return super.getNumber();
}
Теперь я могу назвать это так:
public class Main {
public static void main(String[] args) {
ClassThatOperates<NumberGeneratorAppleWrapper> classThatOperatesApple = new ClassThatOperates<>(new NumberGeneratorAppleWrapper());
ClassThatOperates<NumberGeneratorOrangeWrapper> classThatOperatesOrange = new ClassThatOperates<>(new NumberGeneratorOrangeWrapper());
classThatOperatesApple.doSomeOperation();
classThatOperatesOrange.doSomeOperation();
}
}
И я получаю следующий вывод:
The number with constant is: 14
The number with constant is: 24
Преимущество такого подхода вместо добавления вручную implements NumberGeneratorInterface
к каждому сгенерированному классу состоит в том, что нам не нужно повторять одну и ту же работу послекаждое поколение (которое переопределяет старые классы).Мы только должны добавить новую оболочку, когда генерация приводит к появлению какого-то нового, дополнительного класса.
Я знаю, что в таком сценарии я могу избавиться от обобщений в ClassThatOperates
и просто объявить NumberGeneratorInterface generator;
без <T extends...>
и так далее (и я даже должен), чтобы код был проще, но я хочу сделать этот пример очень похожим на то, что я нашел в каком-то реальном проекте.Я написал: у меня есть, я сделал, я подошел и т. Д., Но на самом деле он основан на уже существующем коде, который я нашел в каком-то проекте.
Есть мои вопросы:
1. Есть лилучшее решение?
2. Является ли это решение так называемым «дурным вкусом»?
3. Если мне придется использовать такое решение, возможно, весь мой подход неверен?
4. Если лучшего решения не существуетдаже если весь подход неверен, что можно улучшить в этом коде (включая избавление от обобщений)?