如何使用两个genericstypes来实现一个接口的Java类?

我有一个通用的接口

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

我有一个类消耗两种types的对象,所以我想要做一些事情:

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

显然我不能那样做。

我当然可以自己实施调度,例如

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

但是我正在寻找generics提供的编译时types检查和调度解决scheme。

我能想到的最好的解决scheme是定义单独的接口,例如

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

在function上,我认为这个解决scheme是可以的。 这只是冗长而丑陋的。

有任何想法吗?

考虑封装:

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

如果创build这些静态内部类困扰你,你可以使用匿名类:

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

由于types擦除,您不能两次实现相同的接口(使用不同的types参数)。

这是基于Steve McLeod的一个可能的解决scheme:

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

问题的隐含要求是共享状态的Consumer<Tomato>Consumer<Apple>对象。 对Consumer<Tomato>, Consumer<Apple>对象的需求来自期望这些参数的其他方法。 我需要一个类实现它们来共享状态。

史蒂夫的想法是使用两个内部类,每个实现一个不同的genericstypes。

该版本为实现Consumer接口的对象添加了getter,然后可以将其传递给期望它们的其他方法。

至less,您可以通过执行如下操作来对您的调度实现进行一些小改进:

 public class TwoTypesConsumer implements Consumer<Fruit> { 

水果是番茄和苹果的祖先。

刚刚陷入了这个。 它刚刚发生,我有同样的问题,但我用不同的方式解决它:我刚刚创build一个这样的新界面

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

不幸的是,这被认为是Consumer<A>而不是所有逻辑Consumer<B> 。 所以你必须在你的课堂里为这样的第二个消费者创build一个小的适配器

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

如果需要Consumer<A>则可以简单地传递this ,如果需要Consumer<B>则只需传递consumerAdapter

您不能直接在一个类中执行此操作,因为通用types的删除和接口声明的重复,无法编译下面的类定义。

 class TwoTypesConsumer implements Consumer<Apple>, Consumer<Tomato> { // cannot compile ... } 

任何其他解决scheme打包相同的消费操作在一个类中需要定义您的类为:

 class TwoTypesConsumer { ... } 

这是没有意义的,因为您需要重复/重复两个操作的定义,并且它们不会从接口引用。 恕我直言,这是一个不好的小和代码重复,我试图避免。

这也可能是一个指标,即在一个类中消耗两个不同的对象(如果它们不是耦合的)有太多的责任。

然而,我正在做什么,你可以做什么是添加显式的工厂对象来创build连接的消费者在以下方式:

 interface ConsumerFactory { Consumer<Apple> createAppleConsumer(); Consumer<Tomato> createTomatoConsumer(); } 

如果实际上这些types真的耦合(相关),那么我build议以这种方式创build一个实现:

 class TwoTypesConsumerFactory { // shared objects goes here private class TomatoConsumer implements Consumer<Tomato> { public void consume(Tomato tomato) { // you can access shared objects here } } private class AppleConsumer implements Consumer<Apple> { public void consume(Apple apple) { // you can access shared objects here } } // It is really important to return generic Consumer<Apple> here // instead of AppleConsumer. The classes should be rather private. public Consumer<Apple> createAppleConsumer() { return new AppleConsumer(); } // ...and the same here public Consumer<Tomato> createTomatoConsumer() { return new TomatoConsumer(); } } 

优点是工厂类知道这两个实现,有一个共享状态(如果需要),如果需要,你可以返回更多耦合的消费者。 没有重复的消耗方法声明不是从接口派生的。

请注意,每个消费者可能是独立的(私人)课程,如果他们不完全相关。

该解决scheme的缺点是更高的类复杂性(即使这可能是一个Java文件),并访问使用方法,你需要一个更多的调用,而不是:

 twoTypesConsumer.consume(apple) twoTypesConsumer.consume(tomato) 

你有:

 twoTypesConsumerFactory.createAppleConsumer().consume(apple); twoTypesConsumerFactory.createTomatoConsumer().consume(tomato); 

总而言之,您可以使用2个内部类在一个顶级类中定义 2个通用消费者,但是在调用的情况下,您需要首先获取适当的实现消费者的引用,因为这不仅仅是一个消费者对象。