我正在尝试为我正在开发的开源项目创建一个API,并且我在尝试扩展API时遇到了速度提升,同时保持语义与当前API一致。我希望能够使用泛型参数定义方法签名,该参数接受调用任何方法签名的结果。通过“ any ”,这意味着包含void
方法。我已经知道你不能直接定义void
的参数类型 - 请不要重复这个明显的事实。不明显的是,是否有任何技巧可以将void
方法调用作为方法的参数提供(即忽略)。
回到故事,所以这更有意义我为什么要做这样的事情,以及我的设计目标和约束是什么,以防上述情况不可能(我担心的是):
我当前的API定义了一个非常可重复的方法模式,如下所示:
public <T,V> Function<T,V> functionFor(V ignoredRetVal) {...}
public <T> Predicate<T> predicateFor(V ignoredRetVal) {...}
public <T> Filter<T> filterFor(V ignoredRetVal) {...}
正如名称所暗示的那样,参数被忽略,甚至在实现中都没有使用。在使用中,ignoredRetVal
被替换为对动态代理的方法调用。由于在调用方法之前评估参数,因此在外部函数(functionFor
或predicateFor
等)之前调用此动态代理方法。动态代理调用记录调用的Method
(或方法链),并将其转换为Function
对象(Guava)或来自多个函数库的其他类似函数的对象。
我现在要做的是创建一个类似的语义,捕获仅用于副作用的方法调用,而不需要返回类型(例如Functional Java's Effect
。提供了非void返回类型,它被忽略。如果提供了void返回类型,它也被忽略并被接受。关键是语义必须以某种方式强制在另一个提取被截取代理的方法之前调用代理方法方法调用。由于我们只对副作用感兴趣,候选方法可能包含void
方法。理想情况下,它看起来像:
public <T, V> Effect<T> effectFor(V ignoredRetVal) {...}
(已经适用于非void返回类型),可以按如下方式使用:
Effect<MyClass> effect1 = effectFor (proxyOfMyClass.nonVoidMethod());// OK :-)
Effect<MyClass> effect2 = effectFor (proxyOfMyClass.orVoidMethod()); // Problem!!
正如我所说,我担心我所寻找的语义不能直接支持。如果没有,那么任何替代方案都应该与我建立的模式精神上接近。此外,我的API的整个目标是减少内部类实现的“垂直噪声”,我不是Double Brace Initializers的粉丝。无论提供什么建议,我都在寻找支持简洁的语义,特别是单语句语义。
答案 0 :(得分:1)
我认为你永远不能强迫void
加入表达式,特别是如果你不喜欢双支撑黑客。
您可以在API设计中关注Mockito的示例。通常,你设置这样的模拟:
when(mockedInstance.someMethod()).thenThrow(new IllegalArgumentException());
但是对于虚空,你这样做:
doThrow(new IllegalArgumentException()).when(mockedInstance).someMethod();
同样,您可以枚举Effect<T>
的方法,使其成为库的静态方法。
E.g。如果Effect<T>
有doSomething()
,那么您可以将其反转,例如
doSomething().onEffectFor(proxyInstanceOfA).methodA();
但是这假设Effect<T>
的相关方法本身不返回值。
如果这不是一个选项,而你需要Effect<T>
,那么你可以使它成为有状态的,如下所示:
VoidEffect<MyType> effect = effectForVoid(proxyOfMyClass);
effect.on().myVoidMethod();
VoidEffect<T>
实现Effect<Void>
,on()
返回传入的代理(或其他代理)。然后,如果在您与IllegalStateException
进行交互之前未调用on()
,则需要抛出effect
。