如何使用两个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个通用消费者,但是在调用的情况下,您需要首先获取适当的实现消费者的引用,因为这不仅仅是一个消费者对象。