181 votes

Comment créer une classe Java qui implémente une interface avec deux types génériques?

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 je voudrais 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.

Je peux bien sûr mettre en œuvre l'expédition de moi-même, par exemple

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 suis à la recherche pour le type de compilation-la vérification et de la solution de répartition que les génériques fournir.

La meilleure solution je pense est de définir des interfaces distinctes, par exemple

public interface AppleConsumer {
   public void consume(Apple a);
}

Fonctionnellement, cette solution est OK, je pense. C'est juste détaillé et le laid.

Des idées?

81voto

Steve McLeod Points 19016

Considérer l'encapsulation:

 public class TwoTypesConsumer {
   private TomatoConsumer tomatoConsumer = new TomatoConsumer();
   private AppleConsumer appleConsumer = new AppleConsumer();

   public void consume(Tomato t) { 
       tomatoConsumer.consume(t);
      }

   public void consume(Apple a) { 
      appleConsumer.consume(a);
   }

  public static class TomatoConsumer implements Consumer<Tomato> {
      public void consume(Tomato t) {  .....  }
  }

  public static class AppleConsumer implements Consumer<Apple> {
      public void consume(Apple a) {  .....  }
  }

}
 

Si la création de ces classes internes statiques vous dérange, vous pouvez utiliser des classes anonymes:

 public class TwoTypesConsumer {

    private Consumer<Tomato> tomatoConsumer = new Consumer<Tomato>() {
        public void consume(Tomato t) {
        }
    };

    private Consumer<Apple> appleConsumer = new Consumer<Apple>() {
        public void consume(Apple a) {
        }
    };

    public void consume(Tomato t) {
        tomatoConsumer.consume(t);
    }

    public void consume(Apple a) {
        appleConsumer.consume(a);
    }

}
 

44voto

Shimi Bandiel Points 3571

En raison de l'effacement de type, vous ne pouvez pas implémenter deux fois la même interface (avec des paramètres de type différents).

13voto

Daphna Shezaf Points 2124

Voici une solution possible basée sur Steve McLeod:

public class TwoTypesConsumer {
   public void consumeTomato(Tomato t) { ... }
   public void consumeApple(Apple a) { ... }

   public Consumer<Tomato> getTomatoConsumer () {
     return new Consumer<Tomato>() {
        public void consume(Tomato t) {
          consumeTomato(t);
        }
   }

   public Consumer<Apple> getAppleConsumer () {
     return new Consumer<Apple>() {
        public void consume(Apple a) {
          consumeApple(t);
        }
   }
}

L'exigence implicite de la question était de Consommation et des objets de Consommation que la part de l'état. La nécessité pour les Consommateurs,les objets de Consommation provient d'autres méthodes qui attendent ces paramètres. J'ai besoin d'une classe de la mettre en œuvre à la fois dans le but de partager de l'état.

Steve idée était d'utiliser deux classes internes, chaque mise en œuvre d'un différent type générique.

Cette version ajoute des getters pour les objets qui implémentent l'interface de Consommateur, qui peut ensuite être transmis à d'autres méthodes attend d'eux.

7voto

Buhb Points 3110

Au moins, vous pouvez apporter une petite amélioration à votre mise en œuvre de dispatch en procédant comme suit:

 public class TwoTypesConsumer implements Consumer<Fruit> {
 

Fruit étant un ancêtre de la tomate et de la pomme.

3voto

Rafael T Points 5817

viens de tomber sur cette. Il vient de se passer, 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 ceci

public interface TwoTypesConsumer<A,B> extends Consumer<A>{
    public void consume(B b);
}

malheureusement, cela est considéré comme Consumer<A> et NON en tant que Consumer<B> contre toute Logique. Donc, vous devez créer un petit Adaptateur pour le deuxième consommateur comme ça à l'intérieur de votre classe

public class ConsumeHandler implements TwoTypeConsumer<A,B>{

    private final Consumer<B> consumerAdapter = new Consumer<B>(){
        public void consume(B b){
            ConsumeHandler.this.consume(B b);
        }
    };

    public void consume(A a){ //...
    }
    public void conusme(B b){ //...
    }
}

si un Consumer<A> est nécessaire, vous pouvez simplement transmettre this, et si, Consumer<B> est nécessaire, il suffit de passer consumerAdapter

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X