#java
Есть некий интерфейс: public interface ViewableParentextends Viewable{ interface ListChangeCallback { void doWhenChange(C object); } ListChangeCallback getAddedSubListCallback(); ListChangeCallback getRemovedSubListCallback(); default ListChangeListener getChangeListener(){ return c -> { while (c.next()){ if (c.wasAdded()) { //Проходимся по добавленным элементам c.getAddedSubList().forEach(e -> { //Вешаем на проперти стиля слушатель, который при изменении стиля потомка меняет стиль у родителя e.styleProperty().addListener((observable, oldValue, newValue) -> refreshStyle(c.getList(), ViewableParent.this,false)); //Выполяняем код add коллбэка if (getAddedSubListCallback()!=null) getAddedSubListCallback().doWhenChange(e); }); //Пересчитываем стиль для родителя исходя из стилей добавляемых потомков refreshStyle(c.getAddedSubList(), ViewableParent.this,true); } else if (c.wasRemoved() || c.wasUpdated()) { //Иначе, если что-то было удалено или обновлено (здесь не уверен в корректности события update) //Так же пересчитываем стиль для родителя refreshStyle(c.getList(), ViewableParent.this, false); //Выполняем код remove коллбэка if (getRemovedSubListCallback()!=null) c.getRemoved().forEach(e -> getRemovedSubListCallback().doWhenChange(e)); } } }; } } Параметр типа C обозначает тип потомка для класса, реализующего данный интерфейс. 4 из 5 классов имеют только один тип потомка, однако есть один класс, в котором потомков 2. Если в объявлении класса 2 раза написать один и тот же интерфейс с разными типами в дженерике, само собой IDE выдает ошибку. Подскажите, каким образом можно обойти данное ограничение с точки зрения архитектуры?
Ответы
Ответ 1
У вас не получится реализовать два раза интерфейс с разными параметризированными типами: interface MyInterface{ T method(); } class MyClass implements MyInterface, MyInterface{ ... } Потому, что происходит стирание типов, и в байткоде остаются только интерфейсы с типом Object. Т.е. для java MyInterface и MyInterface одно и тоже. Если бы даже, не происходило стирания, то возникли бы логические ошибки. Как ранее заметил @zRrr может возникнуть ситуация, что класс реализует два одинаковых метода, с разным возвращаемым типом. public A method(){ ... } public B method(){ ... } При вызове которых, не понятно, что вызывать, и в java такой код не является корректным. Если очень хочется, то можно сделать, но опять же, зависит от сигнатур методов интерфейса и не во всех случаях будет работать. Для интерфейса Comparable это выглядит следующим образом: class A implements Comparable { @Override public int compareTo(A o) { return 0; } } class B implements Comparable { @Override public int compareTo(B o) { return 0; } } //E extends A or B class Gibrid implements Comparable { final A a = new A(); final B b = new B(); @Override public int compareTo(E o) { if (o instanceof A) return a.compareTo((A) o); else if (o instanceof B) return b.compareTo((B) o); throw new IllegalArgumentException("object type is not correct." +"It must be A or B"); } } Но здесь мы уходим от проверки типов во время компиляции во время исполнения программы. Ответ 2
В итоге пришлось отказаться от использования дженерика в описании интерфейса и немного расширить default метод. Не знаю пока, насколько это оправданно и корректно, однако все работает. Единственный момент: не ясно, что в данной ситуации было бы правильней. Вынести интерфейс коллбэка и default метод как статический в утилитарном классе или оставить так? При этом поведение метода переопределять не планируется. public interface ViewableParent extends Viewable{ interface ListChangeCallback{ void doWhenChange(C object); } default ListChangeListener getViewChangeListener(ListChangeCallback addCallback, ListChangeCallback removeCallback){ return c -> { while (c.next()){ if (c.wasAdded()) { //Проходимся по добавленным элементам c.getAddedSubList().forEach(e -> { //Вешаем на проперти стиля слушатель, который при изменении стиля потомка меняет стиль у родителя e.styleProperty().addListener((observable, oldValue, newValue) -> refreshStyle(c.getList(),false)); //Выполяняем код add коллбэка if (addCallback!=null) addCallback.doWhenChange(e); }); //Пересчитываем стиль для родителя исходя из стилей добавляемых потомков refreshStyle(c.getAddedSubList(),true); } else if (c.wasRemoved() || c.wasUpdated()) { //Иначе, если что-то было удалено или обновлено (здесь не уверен в корректности события update) //Так же пересчитываем стиль для родителя refreshStyle(c.getList(),false); //Выполняем код remove коллбэка if (removeCallback!=null) c.getRemoved().forEach(removeCallback::doWhenChange); } } }; } }
Комментариев нет:
Отправить комментарий