Есть некий интерфейс:
public interface ViewableParent<C extends AfdxObject> extends Viewable{
interface ListChangeCallback<C>{
void doWhenChange(C object);
}
ListChangeCallback<C> getAddedSubListCallback();
ListChangeCallback<C> getRemovedSubListCallback();
default ListChangeListener<C> 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 выдает ошибку. Подскажите, каким образом можно обойти данное ограничение с точки зрения архитектуры?
У вас не получится реализовать два раза интерфейс с разными параметризированными типами:
interface MyInterface<T>{
T method();
}
class MyClass implements MyInterface<A>, MyInterface<B>{
...
}
Потому, что происходит стирание типов, и в байткоде остаются только интерфейсы с типом Object
. Т.е. для java
MyInterface<A>
и MyInterface<B>
одно и тоже.
Если бы даже, не происходило стирания, то возникли бы логические ошибки. Как ранее заметил @zRrr может возникнуть ситуация, что класс реализует два одинаковых метода, с разным возвращаемым типом.
public A method(){
...
}
public B method(){
...
}
При вызове которых, не понятно, что вызывать, и в java
такой код не является корректным.
Если очень хочется, то можно сделать, но опять же, зависит от сигнатур методов интерфейса и не во всех случаях будет работать. Для интерфейса Comparable
это выглядит следующим образом:
class A implements Comparable<A> {
@Override
public int compareTo(A o) {
return 0;
}
}
class B implements Comparable<B> {
@Override
public int compareTo(B o) {
return 0;
}
}
//E extends A or B
class Gibrid<E> implements Comparable<E> {
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");
}
}
Но здесь мы уходим от проверки типов во время компиляции во время исполнения программы.
В итоге пришлось отказаться от использования дженерика в описании интерфейса и немного расширить default метод. Не знаю пока, насколько это оправданно и корректно, однако все работает. Единственный момент: не ясно, что в данной ситуации было бы правильней. Вынести интерфейс коллбэка и default метод как статический в утилитарном классе или оставить так? При этом поведение метода переопределять не планируется.
public interface ViewableParent extends Viewable{
interface ListChangeCallback<C>{
void doWhenChange(C object);
}
default <C extends Viewable> ListChangeListener<C> getViewChangeListener(ListChangeCallback<C> addCallback, ListChangeCallback<C> 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);
}
}
};
}
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Имею AutoCompleteTextViewХочу изменить цвет текста, если нет совпадений
Как это происходит? Сайты состоят из html кода, css и js(я про визуальную часть)