创建将调用超类方法的非捕获方法引用
Create non-capturing method reference which will call superclass method
我正在尝试重构以下代码:
class Base {
private Object a, b, <...>; // there's like 10 of these attributes of different type
public Object a() {
return a;
}
public Object b() {
return b;
}
// more getters like the ones above
}
class RootNode extends Base { }
class BranchNode extends Base {
private RootNode root; // passed via constructor
public Object a() {
Object value = super.a();
return value != null ? value : root.a();
}
public Object b() {
Object value = super.b();
return value != null ? value : root.b();
}
// below are more methods like the above one, all with same logic
}
当然,我想删除此代码中的重复项,以免在添加新属性时输入更多相同的行,但我不太清楚该怎么做。
我的第一直觉是它看起来很像这段代码(不幸的是,它无法编译):
private <T> T nvlGet(Function<Base, T> accessor) {
T value = accessor.apply(super); // this is the problem line, because there is no way to pass a "super-reference" to anything
return value != null ? value : accessor.apply(root);
}
// and then public accessors would look like this:
public Object a() {
return nvlGet(Base::a);
}
显然我不能通过调用 accessor.apply(this)
而不是 accessor.apply(super)
来 "fix" 上面的代码,因为那会导致 Stack Overflow
错误。
到目前为止我想出的最接近的方法是使用绑定供应商,如下所示:
private <T> T nvlGet(Supplier<T> first, Supplier<T> second) {
T value = first.get();
return value != null ? value : second.get();
}
public Object a() {
return nvlGet(super::a, root::a);
}
但是,这是我在理想世界中对同一方法的引用次数的两倍。所以,我想知道我是否遗漏了什么,我仍然可以以某种方式修复使用 Function<Base, T>
的版本
正如其他人所说,你不能做得更好,因为 super
不是你可以传递的参考。
我同意 的观点,即传递 super.a()
、super.b()
等调用返回的值更简单。
此外,我会将第二个参数更改为 Function<? super Base, ? extends T>
类型,以便 nvlGet
方法中 root
实例的用法保持封装:
private <T> T nvlGet(T nullable, Function<? super Base, ? extends T> second) {
return nullable != null ? nullable : second.apply(root);
}
用法:
public Object a() {
return nvlGet(super.a(), Base::a);
}
public Object b() {
return nvlGet(super.b(), Base::b);
}
可以使用允许动态处理的动态代理class;使用反射实现接口。然而,它并不像纯反射那样昂贵。
但首先考虑一个替代方案:使用 Optional<A> a()
因为这肯定不那么做作,也不那么巴洛克。
使用接口并创建 InvocationHandler:
interface Abc {
public A a();
public B b();
}
public Class AbcProxy implements InvocationHandler {
private final Object obj;
public AbcProxy(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
try {
...
return ...;
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw e;
}
}
}
用法可能不是很直观,只有a()
、b()
,我无法做出合理的示例代码。所以也许最好从示例代码开始。
没有“超级引用”这样的东西会改变普通调用可覆盖方法(又名 invokevirtual
指令)的结果。
只要您坚持使用函数,您使用两个方法引用的解决方案是您可以获得的最佳解决方案,而传递评估值甚至更简单:
private <T> T nvlGet(T value, Supplier<T> second) {
return value != null? value: second.get();
}
public Object a() {
return nvlGet(super.a(), root::a);
}
我正在尝试重构以下代码:
class Base {
private Object a, b, <...>; // there's like 10 of these attributes of different type
public Object a() {
return a;
}
public Object b() {
return b;
}
// more getters like the ones above
}
class RootNode extends Base { }
class BranchNode extends Base {
private RootNode root; // passed via constructor
public Object a() {
Object value = super.a();
return value != null ? value : root.a();
}
public Object b() {
Object value = super.b();
return value != null ? value : root.b();
}
// below are more methods like the above one, all with same logic
}
当然,我想删除此代码中的重复项,以免在添加新属性时输入更多相同的行,但我不太清楚该怎么做。
我的第一直觉是它看起来很像这段代码(不幸的是,它无法编译):
private <T> T nvlGet(Function<Base, T> accessor) {
T value = accessor.apply(super); // this is the problem line, because there is no way to pass a "super-reference" to anything
return value != null ? value : accessor.apply(root);
}
// and then public accessors would look like this:
public Object a() {
return nvlGet(Base::a);
}
显然我不能通过调用 accessor.apply(this)
而不是 accessor.apply(super)
来 "fix" 上面的代码,因为那会导致 Stack Overflow
错误。
到目前为止我想出的最接近的方法是使用绑定供应商,如下所示:
private <T> T nvlGet(Supplier<T> first, Supplier<T> second) {
T value = first.get();
return value != null ? value : second.get();
}
public Object a() {
return nvlGet(super::a, root::a);
}
但是,这是我在理想世界中对同一方法的引用次数的两倍。所以,我想知道我是否遗漏了什么,我仍然可以以某种方式修复使用 Function<Base, T>
正如其他人所说,你不能做得更好,因为 super
不是你可以传递的参考。
我同意 super.a()
、super.b()
等调用返回的值更简单。
此外,我会将第二个参数更改为 Function<? super Base, ? extends T>
类型,以便 nvlGet
方法中 root
实例的用法保持封装:
private <T> T nvlGet(T nullable, Function<? super Base, ? extends T> second) {
return nullable != null ? nullable : second.apply(root);
}
用法:
public Object a() {
return nvlGet(super.a(), Base::a);
}
public Object b() {
return nvlGet(super.b(), Base::b);
}
可以使用允许动态处理的动态代理class;使用反射实现接口。然而,它并不像纯反射那样昂贵。
但首先考虑一个替代方案:使用 Optional<A> a()
因为这肯定不那么做作,也不那么巴洛克。
使用接口并创建 InvocationHandler:
interface Abc {
public A a();
public B b();
}
public Class AbcProxy implements InvocationHandler {
private final Object obj;
public AbcProxy(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
try {
...
return ...;
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw e;
}
}
}
用法可能不是很直观,只有a()
、b()
,我无法做出合理的示例代码。所以也许最好从示例代码开始。
没有“超级引用”这样的东西会改变普通调用可覆盖方法(又名 invokevirtual
指令)的结果。
只要您坚持使用函数,您使用两个方法引用的解决方案是您可以获得的最佳解决方案,而传递评估值甚至更简单:
private <T> T nvlGet(T value, Supplier<T> second) {
return value != null? value: second.get();
}
public Object a() {
return nvlGet(super.a(), root::a);
}