我有这样的界面:
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中是否可行,如果是这样,最简单的方法是什么?
答案 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将扩展OneArgStuffDoer
或TwoArgStuffDoer
,并实现前者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 }
}
干净整洁!没错!?!
希望有所帮助!