J'ai une interface générique
public interface Consumer<E> {
public void consume(E e);
}
J'ai une classe qui consomme deux types d'objets, donc j'aimerais faire quelque chose comme:
public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
public void consume(Tomato t) { ..... }
public void consume(Apple a) { ...... }
}
Apparemment, je ne peux pas faire ça.
Je peux bien sûr mettre en œuvre l'envoi moi-même,
public class TwoTypesConsumer implements Consumer<Object> {
public void consume(Object o) {
if (o instanceof Tomato) { ..... }
else if (o instanceof Apple) { ..... }
else { throw new IllegalArgumentException(...) }
}
}
Mais je recherche la solution de vérification de type et de répartition au moment de la compilation fournie par les génériques.
La meilleure solution à laquelle je puisse penser est de définir des interfaces séparées, par exemple
public interface AppleConsumer {
public void consume(Apple a);
}
Fonctionnellement, cette solution est OK, je pense. C'est juste verbeux et moche.
Des idées?
java
generics
interface
multiple-inheritance
daphshez
la source
la source
Réponses:
Pensez à l'encapsulation:
Si la création de ces classes internes statiques vous dérange, vous pouvez utiliser des classes anonymes:
la source
TwoTypesConsumer
remplit aucun contrat, alors à quoi ça sert? Il ne peut pas être transmis à une méthode qui souhaite l'un ou l'autre type deConsumer
. L'idée même d'un consommateur à deux types serait que vous pouvez le donner à une méthode qui veut un consommateur de tomate ainsi qu'à une méthode qui veut un consommateur de pomme. Ici, nous n'avons ni l'un ni l'autre.TwoTypesConsumer
instance englobante si nécessaire, puis vous pouvez passertwoTypesConsumer.getAppleConsumer()
à une méthode qui souhaite un consommateur Apple. Une autre option serait d'ajouter des méthodes similairesaddConsumer(Producer<Apple> producer)
à TwoTypesConsumer.ExceptionMapper
) ...En raison de l'effacement de type, vous ne pouvez pas implémenter la même interface deux fois (avec des paramètres de type différents).
la source
Voici une solution possible basée sur celle de Steve McLeod :
L'exigence implicite de la question était
Consumer<Tomato>
et lesConsumer<Apple>
objets qui partagent l'état. Le besoin d'Consumer<Tomato>, Consumer<Apple>
objets provient d'autres méthodes qui les attendent comme paramètres. J'ai besoin d'une classe pour les implémenter tous les deux afin de partager l'état.L'idée de Steve était d'utiliser deux classes internes, chacune implémentant un type générique différent.
Cette version ajoute des getters pour les objets qui implémentent l'interface Consumer, qui peuvent ensuite être passés à d'autres méthodes qui les attendent.
la source
Consumer<*>
instances dans les champs d'instance si elleget*Consumer
est appelée souvent.Au moins, vous pouvez apporter une petite amélioration à votre implémentation de la répartition en procédant comme suit:
Fruit étant un ancêtre de la tomate et de la pomme.
la source
Je suis juste tombé dessus. C'est juste arrivé, que j'ai eu le même problème, mais je l'ai résolu d'une manière différente: je viens de créer une nouvelle interface comme celle-ci
malheureusement, ceci est considéré comme
Consumer<A>
et PAS commeConsumer<B>
contre tout Logic. Vous devez donc créer un petit adaptateur pour le deuxième consommateur comme celui-ci dans votre classesi un
Consumer<A>
est nécessaire, vous pouvez simplement passerthis
, et siConsumer<B>
nécessaire, passez simplementconsumerAdapter
la source
Vous ne pouvez pas le faire directement dans une classe car la définition de classe ci-dessous ne peut pas être compilée en raison de l'effacement des types génériques et de la déclaration d'interface en double.
Toute autre solution pour regrouper les mêmes opérations de consommation dans une classe nécessite de définir votre classe comme:
ce qui est inutile car vous devez répéter / dupliquer la définition des deux opérations et elles ne seront pas référencées depuis l'interface. IMHO faire cela est une mauvaise petite duplication de code que j'essaie d'éviter.
Cela peut également indiquer qu'il y a trop de responsabilité dans une classe pour consommer 2 objets différents (s'ils ne sont pas couplés).
Cependant, ce que je fais et ce que vous pouvez faire est d'ajouter un objet d'usine explicite pour créer des consommateurs connectés de la manière suivante:
Si en réalité ces types sont vraiment couplés (liés), je recommanderais de créer une implémentation de cette manière:
L'avantage est que la classe de fabrique connaît les deux implémentations, il existe un état partagé (si nécessaire) et vous pouvez renvoyer davantage de consommateurs couplés si nécessaire. Il n'y a pas de déclaration de méthode de consommation répétée qui ne soit pas dérivée de l'interface.
Veuillez noter que chaque consommateur peut être une classe indépendante (toujours privée) s'il n'est pas complètement lié.
L'inconvénient de cette solution est une complexité de classe plus élevée (même s'il peut s'agir d'un seul fichier java) et pour accéder à la méthode de consommation, vous avez besoin d'un appel supplémentaire au lieu de:
vous avez:
Pour résumer, vous pouvez définir 2 consommateurs génériques dans une classe de premier niveau en utilisant 2 classes internes, mais en cas d'appel, vous devez d'abord obtenir une référence au consommateur d' implémentation approprié car il ne peut pas s'agir simplement d'un objet consommateur.
la source
Dans le style fonctionnel, il est assez facile de le faire sans implémenter l'interface et il effectue également la vérification du type au moment de la compilation.
Notre interface fonctionnelle pour consommer l'entité
notre responsable pour traiter et consommer l'entité de manière appropriée
la source
Une autre alternative pour éviter l'utilisation de plus de classes. (exemple utilisant java8 +)
la source
Désolé de répondre à de vieilles questions, mais j'aime vraiment ça! Essayez cette option:
Je pense que c'est ce que vous recherchez.
Vous obtenez cette sortie:
la source