Java可选参数化接口

时间:2018-04-11 23:19:04

标签: java interface java-8 abstract parameterized-types

我有这样的界面:

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

    default void doStuff(T val) {}
}

界面背后的想法是你可以实现一个或其他方法。那么我有一个像这样的抽象类:

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

但是我很难让抽象类使用它。因为虽然我可以将我的抽象类更改为:

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

这会改变实现类,如下所示:

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

哪个有效,但......这不是一个干净的解决方案。它也会让我重构所有现有的实现。

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

  

实现Foo接口时,可以实现2中的任何一个   接口中指定的方法。如果您正在实施单一   参数方法,doStuff(T val),你只需要指定1   参数化类型。但是,如果你正在实施双重   参数方法,doStuff(S val1,T val2),你必须同时指定   参数化类型。

这在Java中是否可行,如果是这样,最简单的方法是什么?

1 个答案:

答案 0 :(得分:4)

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

您的规范,实现必须做“这个或那个”闻起来像是违反了接口隔离原则。这就是SOLID原则的“我”。

因此,为了解决这个问题,我们希望用抽象来表示操作:

public interface StuffDoer {
  void run();
}

冷却。这很简单。所以现在你想要一个1-arg的东西和2-arg的东西呢。但每个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 }
}

干净整洁!没错!?!

希望有所帮助!