Search code examples
javagenericsinterfacemultiple-inheritance

How to make a Java class that implements one interface with two generic types?


I have a generic interface

public interface Consumer<E> {
    public void consume(E e);
}

I have a class that consumes two types of objects, so I would like to do something like:

public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
   public void consume(Tomato t) {  .....  }
   public void consume(Apple a) { ...... }
}

Apparently I can't do that.

I can of course implement the dispatch myself, e.g.

public class TwoTypesConsumer implements Consumer<Object> {
   public void consume(Object o) {
      if (o instanceof Tomato) { ..... }
      else if (o instanceof Apple) { ..... }
      else { throw new IllegalArgumentException(...) }
   }
}

But I am looking for the compile-time type-checking and dispatching solution that generics provide.

The best solution I can think of is to define separate interfaces, e.g.

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

Functionally, this solution is OK, I think. It's just verbose and ugly.

Any ideas?


Solution

  • Consider 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) {  .....  }
        }
    }
    

    If creating these static inner classes bothers you, you can use anonymous classes:

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