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 实现将扩展 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 }
}
干净整洁!对吧!?!
希望对您有所帮助!
我有这样的界面:
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 实现将扩展 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 }
}
干净整洁!对吧!?!
希望对您有所帮助!