如何创建一个实现具有两个泛型类型的接口的Java类?

dap*_*hez 158 java generics interface multiple-inheritance

我有一个通用的界面

public interface Consumer<E> {
    public void consume(E e);
}
Run Code Online (Sandbox Code Playgroud)

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

public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
   public void consume(Tomato t) {  .....  }
   public void consume(Apple a) { ...... }
}
Run Code Online (Sandbox Code Playgroud)

显然我做不到.

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

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

但我正在寻找泛型提供的编译时类型检查和调度解决方案.

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

public interface AppleConsumer {
   public void consume(Apple a);
}
Run Code Online (Sandbox Code Playgroud)

从功能上讲,我认为这个解决方案没问题.它只是冗长而丑陋.

有任何想法吗?

Ste*_*eod 74

考虑封装:

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) {  .....  }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 但是`TwoTypesConsumer`履行了*no*contract,那么重点是什么?它不能传递给需要任何类型的"Consumer"的方法.两种类型的消费者的整个想法是,你可以把它给一个想要一个番茄消费者的方法以及一个想要一个苹果消费者的方法.在这里我们都没有. (99认同)
  • 我会说:这是一个带有Java的**缺陷.如果实现采用不同的参数,那么绝对没有理由不允许我们拥有相同接口的多个实现. (10认同)
  • 不知何故,看起来像代码重复......我遇到了同样的问题,没有找到其他看起来干净的解决方案。 (2认同)

Shi*_*iel 39

由于类型擦除,您无法两次实现相同的接口(具有不同的类型参数).

  • 我可以看到这是一个什么问题...问题是什么是绕过这个问题的最好(最有效,最安全,优雅)的方法. (6认同)
  • 在不涉及业务逻辑的情况下,此处的“气味”类似于“访客”模式。 (2认同)

dap*_*hez 12

这是一个基于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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题的隐含要求是Consumer<Tomato>Consumer<Apple>共享状态的对象.Consumer<Tomato>, Consumer<Apple>对象的需求来自于将这些作为参数的其他方法.我需要一个类来实现它们以便共享状态.

史蒂夫的想法是使用两个内部类,每个类实现不同的泛型类型.

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

  • 如果有人使用它:值得经常调用`get * Consumer`的情况下将`Consumer &lt;*&gt;`实例存储在实例字段中。 (2认同)

Buh*_*uhb 7

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

public class TwoTypesConsumer implements Consumer<Fruit> {
Run Code Online (Sandbox Code Playgroud)

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

  • 谢谢,但无论专业人士说什么,我都不认为番茄是水果.不幸的是,除了Object之外没有共同的基类. (12认同)
  • 您始终可以创建一个名为:AppleOrTomato 的基类;) (2认同)