Общий интерфейс с обратной зависимостью - PullRequest
6 голосов
/ 09 августа 2011

Я хочу создать два интерфейса с обратными отношениями.

public interface Item <D extends Description,
                                        C extends Category<D,Item<D,C>>> {
    public C getCategory();
    public void setCategory(C category);}

Я не уверен, что выражение C extends Category<D,Item<D,C>> правильное, но по крайней мере ошибок компилятора нет.

public interface Category<D extends Description, I extends Item> {
    public List<I> getItems();
    public void setItems(List<I> items);}

I extends Item выдает предупреждение Item is a raw type. References to Item<D,C> should be parametrized. Я пытался

I extends Item<D,Category<D,I>>

но это приводит к ошибке Bound mismatch: The type Category<D,I> is not a valid substitute for the bounded parameter <C extends Category<D,Item<D,C>>> of the type Item<D,C>. Как правильно параметризовать интерфейс Category с помощью дженериков?

Ответы [ 5 ]

2 голосов
/ 09 августа 2011

Это похоже на работу :).Я понятия не имею, как это объяснить (я обычно стараюсь избегать подобных вещей), но здесь это так:

interface Description {}

interface Item<D extends Description, I extends Item<D, I, C>, C extends Category<D, C, I>>
{
    public C getCategory();   
    public void setCategory(C category);

}

interface Category<D extends Description, C extends Category<D, C, I>, I extends Item<D, I, C>> {    
    public List<I> getItems();   
    public void setItems(List<I> items);
}

class DescriptionImpl implements Description {}

class CustomItem implements Item<DescriptionImpl, CustomItem, CustomCategory> {
    public CustomCategory getCategory() {
        return null;  
    }

    public void setCategory(CustomCategory category) {
    }
}

class CustomCategory implements Category<DescriptionImpl, CustomCategory, CustomItem> {

    public List<CustomItem> getItems() {
        return null;          }

    public void setItems(List<CustomItem> items) {
    }
}

Теперь, если вы сделаете это:

CustomCategory customCategory = new CustomCategory();
CustomItem customItem = new CustomItem();
DescriptionImpl description = new DescriptionImpl();

customItem.getCategory();

типкатегории, возвращаемой customItem.getCategory(), является CustomCategory, которая, я думаю, именно то, что вы на самом деле хотите.

0 голосов
/ 09 августа 2011

Рассмотрим эту упрощенную задачу

interface Item<C extends Container<Item<C>>>

interface Container<I extends Item<Container<I>>>

Это не работает, потому что подтипы Container<Item<C>> довольно ограничены - Container<MyItem> не является его подтипом, так же как List<string> не является подтипом List<Object>

Мы можем расслабиться с подстановочными знаками:

interface Item<C extends Container<? extends Item<C>>>

interface Container<I extends Item<? extends Container<I>>>

Теперь все отлично работает

class MyItem implements Item<MyContainer>

class MyContainer implements Container<MyItem>

в основном. Следующее объявление также допускается, но не то, что мы намеревались

class HerItem implements Item<MyContainer>  // nooo!

Это потому, что мы слишком ослабили ограничения. Ну, это не очень серьезная проблема. Конечно, наша система типов не такая жесткая, как хотелось бы (система типов не существует), но программисты инстинктивно следуют намеченным ограничениям, не выходя из своих способов писать причудливые вещи только потому, что могут.

В идеале нам нужен тип This, и наши предполагаемые ограничения могут быть выражены как

interface Item<C extends Container<This>>>

interface Container<I extends Item<This>>

Поскольку у нас нет This, можно попытаться приблизиться к нему с помощью параметра типа

interface Item<C extends Container<This, C>>, This extends Item<C, This> >

interface Container<I extends Item<This, I>, This extends Container<I, This>>

(или, более симметрично

    interface Item<C extends Container<I, C>>, I extends Item<C, I> >

    interface Container<I extends Item<C, I>, C extends Container<I, C>>

) Тем не менее, это не так уж и сложно. This на самом деле не «этот тип». Можно

class HerItem implements Item<MyContainer, MyItem> // uh?

Еще раз, мы должны полагаться на дисциплину программиста, чтобы не делать такие вещи.

0 голосов
/ 09 августа 2011

Давайте сначала забудем об описании и просто создадим несколько приятных симметричных интерфейсов:

 interface Item<C extends Category<Item<C>>> {}

 interface Category<I extends Item<Category<I>>> {}

Для Описаний вам могут потребоваться два разных типа описания для Элемента и Категории.

Вкл.более общее замечание, я не уверен, что ваш дизайн - хорошая идея.Я не знаю, для чего вы будете его использовать, но похоже, что это будет сложно использовать правильно.

Кроме того, что-то не так с item.setCategory(c), поскольку item уже параметризован категорией.

0 голосов
/ 09 августа 2011

Найдите время, чтобы прочитать это: http://www.artima.com/forums/flat.jsp?forum=106&thread=136394&start=15&msRange=15#180733

0 голосов
/ 09 августа 2011

Компилируется без предупреждений:

interface Description {}

interface Item<D extends Description, C extends Category<D, Item<D, C>>> {
    public C getCategory();
    public void setCategory(C category);
}

public interface Category<D extends Description, I extends Item<D, ?>> {
    public List<I> getItems();
    public void setItems(List<I> items);
}

Я сделал I extends Item<D, ?>.Хотя здесь нет предупреждений, это может вызвать другие проблемы - дайте мне знать, если это произойдет, и я посмотрю, что я могу сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...