如何在java中扩展下面的API函数而不导致歧义
How to extend the following API function in java and not lead to ambiguous
我有一些现有的重载 API:
1). foo(a, b) { return foo(a, b, null); }
2). foo(a, b, c) {return foo(a,b,c,null);}
3). foo(a, b, c, d) { implement of the function...; }
其中a,b,c是一些数据结构,其值也可以为null。
现在我需要用一个标志来扩展 APIs。即
4). foo(a, b, Boolean flag)
5). foo(a, b, c, Boolean flag)
6). foo(a, b, c, d, Boolean flag)
其中布尔值可以是null/false/true;
为了兼容性,现有的 API 应该仍然存在。
问题是:调用 foo(a, b, null) 时,2) 和 4) 不明确。 3) 和 5).
也一样
我的问题:一般来说,我们应该如何扩展新 API?
如果你使用Java8,你应该使用OptionalBoolean而不是Boolean。它不如它的同伴 Optional<>
、OptionalInt
、OptionalDouble
等,但在这种情况下,它可能是一个真正的好处。
由于提到的 OptionalBoolean 确实来自 com.sun.javafx.scene.control.behavior.OptionalBoolean
,因此可能有更好的选择。
我个人尽量避免在有更好选择的地方使用 null
。
而不是
class Foo {
Bar s; // whatever Bar is...
Foo() {
Foo(null)
}
Foo(Bar s) {
this.s = s;
}
public void doStuff() {
if (s != null) {
bar.frobnicate();
}
}
}
最好有
class Foo {
Bar s; // whatever Bar is...
Foo() {
Foo(Bar.EMPTY_VALUE)
}
Foo(Bar s) {
this.s = s;
}
public void doStuff() {
bar.frobnicate();
}
}
与 Bar
有一个
public final static EMPTY_VALUE = new Bar() {
// redefine it so that frobnicate() just does nothing.
// This way, EMPTY_VALUE can be used wherever appropriate
}
这叫做Null Object pattern。虽然它没有直接解决您的问题,但它通过在各处使用 null
解决了您的歧义。
解决它们的另一种方法是让每个构造函数直接调用 "main constructor"。
这样你就可以
foo(a, b) { return foo(a, b, null, null); }
foo(a, c) { return foo(a, null, c, null); }
foo(a, b, c) {return foo(a,b,c,null);}
foo(a, b, d) {return foo(a,b,null, c);}
foo(a, b, c, d) { implement of the function...; }
读起来还不如更清楚
a) 您可以为新方法指定一个不同的名称。 fooWithFlag
b) 你不能允许 null
(大概它和以前没有标志的方法做同样的事情),而是使用原语 boolean
而不是
c) 您可以创建一个子接口 ServiceWithFlags
或 ServiceV2
并将新方法仅放在该接口上。新代码可以通过新接口来使用它,旧代码仍然使用旧接口,不会看到方法。
d) 这只是一个编译时错误。这不会破坏已经编译的代码。所以你实际上可以继续并添加你的新方法。编译器会捕获任何歧义,并在开发过程中轻松修复。
您可以使用枚举作为具有三种状态的标志,而不仅仅是一个布尔标志。
回答我的问题:
我觉得这样调用会避免歧义:
对于 2) foo(a, b, c) 和 4) foo(a, b, Boolean) 如果
我这样调用:foo(x, y, Boolean(null)) 而不是 foo(x, y, null),
这样就避免了歧义。
我有一些现有的重载 API:
1). foo(a, b) { return foo(a, b, null); }
2). foo(a, b, c) {return foo(a,b,c,null);}
3). foo(a, b, c, d) { implement of the function...; }
其中a,b,c是一些数据结构,其值也可以为null。 现在我需要用一个标志来扩展 APIs。即
4). foo(a, b, Boolean flag)
5). foo(a, b, c, Boolean flag)
6). foo(a, b, c, d, Boolean flag)
其中布尔值可以是null/false/true; 为了兼容性,现有的 API 应该仍然存在。
问题是:调用 foo(a, b, null) 时,2) 和 4) 不明确。 3) 和 5).
也一样我的问题:一般来说,我们应该如何扩展新 API?
如果你使用Java8,你应该使用OptionalBoolean而不是Boolean。它不如它的同伴 Optional<>
、OptionalInt
、OptionalDouble
等,但在这种情况下,它可能是一个真正的好处。
由于提到的 OptionalBoolean 确实来自 com.sun.javafx.scene.control.behavior.OptionalBoolean
,因此可能有更好的选择。
我个人尽量避免在有更好选择的地方使用 null
。
而不是
class Foo {
Bar s; // whatever Bar is...
Foo() {
Foo(null)
}
Foo(Bar s) {
this.s = s;
}
public void doStuff() {
if (s != null) {
bar.frobnicate();
}
}
}
最好有
class Foo {
Bar s; // whatever Bar is...
Foo() {
Foo(Bar.EMPTY_VALUE)
}
Foo(Bar s) {
this.s = s;
}
public void doStuff() {
bar.frobnicate();
}
}
与 Bar
有一个
public final static EMPTY_VALUE = new Bar() {
// redefine it so that frobnicate() just does nothing.
// This way, EMPTY_VALUE can be used wherever appropriate
}
这叫做Null Object pattern。虽然它没有直接解决您的问题,但它通过在各处使用 null
解决了您的歧义。
解决它们的另一种方法是让每个构造函数直接调用 "main constructor"。
这样你就可以
foo(a, b) { return foo(a, b, null, null); }
foo(a, c) { return foo(a, null, c, null); }
foo(a, b, c) {return foo(a,b,c,null);}
foo(a, b, d) {return foo(a,b,null, c);}
foo(a, b, c, d) { implement of the function...; }
读起来还不如更清楚
a) 您可以为新方法指定一个不同的名称。 fooWithFlag
b) 你不能允许 null
(大概它和以前没有标志的方法做同样的事情),而是使用原语 boolean
而不是
c) 您可以创建一个子接口 ServiceWithFlags
或 ServiceV2
并将新方法仅放在该接口上。新代码可以通过新接口来使用它,旧代码仍然使用旧接口,不会看到方法。
d) 这只是一个编译时错误。这不会破坏已经编译的代码。所以你实际上可以继续并添加你的新方法。编译器会捕获任何歧义,并在开发过程中轻松修复。
您可以使用枚举作为具有三种状态的标志,而不仅仅是一个布尔标志。
回答我的问题:
我觉得这样调用会避免歧义: 对于 2) foo(a, b, c) 和 4) foo(a, b, Boolean) 如果 我这样调用:foo(x, y, Boolean(null)) 而不是 foo(x, y, null), 这样就避免了歧义。