2011-08-09 12 views
6

Quiero crear dos interfaces con relaciones inversas.Interfaz genérica con relación inversa

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

no estoy seguro de si la expresión C extends Category<D,Item<D,C>> es correcta, pero al menos no hay errores de compilación.

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

I extends Item da el aviso Item is a raw type. References to Item<D,C> should be parametrized. Probé

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

pero esto resulta en el error 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>. ¿Cómo parametrizo correctamente la interfaz Category con genéricos?

Respuesta

2

Esto parece funcionar :). No tengo idea de cómo explicarlo (normalmente intenta evitar hacer cosas por el estilo), pero aquí va:

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) { 
    } 
} 

Ahora bien, si usted hace esto:

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

customItem.getCategory(); 

del tipo de la categoría obtenida por el customItem.getCategory() es CustomCategory, que creo que es lo que realmente quieres.

+0

¡Parece extraño pero parece funcionar! – Thor

+0

Sí :) Es más extraño para mí porque no puedo explicarlo :)) –

0

Esto compila sin advertencias:

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); 
} 

hice I extends Item<D, ?>. Aunque esto no tiene advertencias, esto puede causarte otros problemas. Avísame si lo hace y veré qué puedo hacer.

+0

Como sé * qué tipo de artículo tengo, no creo que sea '' lo que quiero usar. – Thor

0

Olvidémonos de la descripción en un primer momento y simplemente hacer algunas lindas interfaces simétricas:

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

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

para las descripciones, es posible que desee dos tipos descripción diferente para Artículo y Categoría.

En una nota más general, no estoy seguro de que su diseño sea una buena idea. No sé para qué lo utilizará, pero parece algo difícil de usar.

Además, algo parece incorrecto con item.setCategory(c) ya que item ya está parametrizado por una categoría.

0

consideran este problema simplificado

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

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

no funciona, porque subtipos de Container<Item<C>> son bastante limitados - Container<MyItem> no es un subtipo de la misma, al igual que List<string> no es un subtipo de List<Object>

Podemos relajarlo con comodines:

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

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

Ahora funciona bien

class MyItem implements Item<MyContainer> 

class MyContainer implements Container<MyItem> 

en su mayoría.También se permite la siguiente declaración, pero no lo que pretende

class HerItem implements Item<MyContainer> // nooo! 

Esto se debe a que las limitaciones relajamos demasiado. Bueno, no es un problema realmente serio. Claro, nuestro sistema de tipos no es tan estricto como queremos (no es un sistema de tipos), pero los programadores instintivamente seguirían las restricciones previstas, no se desviejen para escribir cosas raras solo porque pueden hacerlo.

Idealmente, querría un tipo This, y nuestras limitaciones debido puede ser expresado como

interface Item<C extends Container<This>>> 

interface Container<I extends Item<This>> 

Dado que no tenemos This, se podría intentar acercarse a ella por un parámetro de tipo

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

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

(o, más simétricamente

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

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

) Sin embargo, esto tampoco es realmente ajustado. This no es realmente el "este tipo". Es posible

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

Una vez más, debemos confiar en la disciplina del programador para no hacer cosas como esa.

Cuestiones relacionadas