Java 可选的参数化接口

Java Optional Parametrized Interfaces

我有这样的界面:

public interface Foo<T> {
    default void doStuff(T val1, T val2) {}

    default void doStuff(T val) {}
}

接口背后的想法是您可以实现其中一种或另一种方法。那么我有一个抽象的 class 像这样:

abstract public class AbstractFoo<T> implements Foo<T> {
    //Bunch of Stuff
}

最后是这样的实现:

public class AwesomeOne extends AbstractFoo<String> {
    @Override
    public void doStuff(String val) {
        //Do Stuff
    }
}

这是另一个实现的例子:

public class AwesomeTwo extends AbstractFoo<String> {
    @Override
    public void doStuff(String val1, String val2) {
        //Do Stuff
    }
}

这很好用。现在,我希望能够为 doStuff(val1, val2) 方法指定 2 种不同的类型。所以我希望能够做这样的事情:

public class AwesomeThree extends AbstractFoo<String, Double> {
    @Override
    public void doStuff(String val1, Double val2) {
        //Do Stuff
    }
}

这就是我的界面将如何改变:

public interface Foo<S, T> {
    default void doStuff(S val1, T val2) {}

    default void doStuff(T val) {}
}

但是我很难让摘要 class 处理这个问题。因为虽然我可以将我的摘要 class 更改为:

abstract public class AbstractFoo<S, T> implements Foo<S, T> {
    //Bunch of Stuff
}

那会改变实现 classes 像这样:

public class AwesomeOne extends AbstractFoo<Object, String> {
    @Override
    public void doStuff(String val) {
        //Do Stuff
    }
}

这行得通,但是....这不是一个真正干净的解决方案。这也会让我重构所有现有的实现。

基本上用简单的英语我想说:

When implementing the Foo interface, you can implement either of the 2 methods specified in the interface. If you are implementing the single parameter method, doStuff(T val), you only need to specify 1 parametrized type. If, however, you are implementing the double parameter method, doStuff(S val1, T val2), you have to specify both parameterized types.

这在 Java 中可行吗?如果可行,解决此问题的最简洁方法是什么?

您违反了一些 OO 原则,这就是设计感觉不干净的原因。

你关于实现必须执行的规范 "this or that" 在我看来违反了 接口隔离 原则。这就是 SOLID 原则的 "I"。

所以为了解决这个问题,我们想用抽象来表示操作:

public interface StuffDoer {
  void run();
}

酷。这很简单。所以现在你想要一个 1-arg stuff doer 和一个 2-arg stuff doer。但是每个 StuffDoer 必须能够 run()。看?现在只有一种强制方法。

public abstract class OneArgStuffDoer<T1> implements StuffDoer {
  private final T1 arg;
  public OneArgStuffDoer(T1 arg) {
    this.arg = Objects.requireNonNull(arg);
  }
  public final void run() {
    run(arg);
  }
  abstract void run(T1 arg);
}

您可以与 TwoArgStuffDoer 玩类似的游戏。现在,您的 API 实现将扩展 OneArgStuffDoerTwoArgStuffDoer,并实现前者的 run(T1 arg) 或后者的 run(T1 arg1, T2 arg2)

这是 AwesomeOne 的样子:

public final class AwesomeOne extends OneArgStuffDoer<String> {
  @Override
  void run(String str) { // do your awesome stuff here }
}

干净整洁!对吧!?!

希望对您有所帮助!