2011-10-26 3 views
2

Au lieu d'utiliser if/else, j'aimerais utiliser une carte pour obtenir une implémentation concrète. Je voudrais utiliser des génériques pour déclarer un gestionnaire d'entité spécifique qui gère une entité spécifique mais j'ai le problème que le gestionnaire accepte simplement les extensions de mon interface d'entité. Le code ressemble à ceci:Java Génériques avec "extends"

private Map<Class<IEntity>, IEntityHandler> handlers; 

public void callingMethod(IModel model) { 
    for (IEntity entity : model.getObjects()) { 
    // handle accepts just IDevice and not IEntity ! 
    handlers.get(entity).handle(entity); 
    } 
} 

public interface IEntityHandler<T extends IEntity> { 
    handle(T entity); 
} 

public class DeviceHandler implements IEntityHandler<IDevice> { 
    @Override 
    public void handle(IDevice deviceEntity) { 
    // do something 
    } 
} 

Comment puis-je obtenir ma méthode de gestion qui prend IEntity? IDevice s'étend depuis IEntity.

Répondre

1

Déclare carte vous que:

Map<Class<T extends IEntity>, IEntityHandler> handlers. 
+1

Je ne pense pas qu'il ait un paramètre de type 'T' dans la classe qui a la carte comme champ. Cela ne serait pas possible puisque la carte devrait être capable de contenir des gestionnaires pour une variété de classes différentes. C'est tout le but. –

+0

Cela fonctionne !! Merci! – myborobudur

0
private Map<? extends IEntity, ? extends IEntityHandler> handlers; 
+0

Il doit mapper les objets 'Class' aux gestionnaires, et non les instances de' IEntity' aux gestionnaires. –

+0

Ici, je reçois cette erreur de construction: La méthode handle (capture # 1-de? Extends IEntity) dans le type IEntityHandler n'est pas applicable pour les arguments (IEntity) – myborobudur

0
private Map<Class<? extends IEntity>, ? extends IEntityHandler> handlers; 
+1

Cela entraînera des problèmes lors de la tentative de placement des gestionnaires dans la carte. En utilisant '? extends ... 'pour un type param dans une déclaration de collection ne fonctionne généralement pas bien lorsque vous avez l'intention d'ajouter directement des entrées à la collection pour les raisons [expliqué ici] (http://download.oracle.com/javase/tutorial /java/generics/wildcards.html). –

+0

Oui, vous avez raison. Il devrait être juste IEntityHandler – Mikel

+0

Même ici l'erreur de construction: Le handle de méthode (capture # 1-of? Extends IEntity) dans le type IEntityHandler n'est pas applicable pour les arguments (IEntity) – myborobudur

1

Tout d'abord, vous aurez besoin de changer cette ligne ...

handlers.get(entity).handle(entity); 

à cette ...

handlers.get(entity.getClass()).handle(entity); 

Puis, comme les autres l'ont dit, il vaudrait mieux changer le paramètre de type Class<IEntity> de votre carte en Class<? extends IEntity>, puisque vous voulez mapper des classes concrètes aux gestionnaires.

Si vous le faites comme ça, vous n'obtiendrez pas d'erreur. Seul un avertissement car le paramètre de type IEntityHandler dans votre carte est un type brut. Mais si vous essayez de le changer en ? extends IEntityHandler ou en IEntityHandler<? extends IEntity>, vous obtiendrez une erreur de compilation lors de l'affectation ou du remplissage de la carte.

Donc je vous suggère de simplement faire les changements ci-dessus (getClass() et Class<? extends IEntity>), puis simplement supprimer l'avertissement avec une annotation. Tant que votre carte est correctement remplie avec le bon gestionnaire pour la bonne classe, vous ne rencontrerez pas de problèmes.

+0

Vous avez absolument raison! Merci pour votre explication détaillée. – myborobudur

0

Je pense que ce que vous allez vers est une (respiration profonde) typesafe hetereogeneous container. Toutefois, étant donné que les objets que vous souhaitez stocker sont eux-mêmes génériques, vous devez utiliser super type tokens.

Je pense que vous avez besoin alors d'introduire et apprivoiser un caractère générique en réécrivant la boucle supérieure comme ceci:

for (IEntity entity: model.getObjects()) { 
    handle(entity); 
} 

private <T extends IEntity> handle(T entity) { 
    IEntityHandler<T> handler = ... get appropriate handler from THC ... 
    handler.handle(entity); 
} 

Je ne suis pas sûr à ce sujet, cependant. C'est un croquis assez grossier.