8

我正在尝试为我正在从事的开源项目创建 API,并且在尝试扩展 API 同时保持语义与当前 API 一致时遇到了障碍。我希望能够定义一个带有通用参数的方法签名,该参数接受调用任何方法签名的结果。“任何”意味着包括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)或其他类似函数的对象。

我现在要做的是创建一个类似的语义,该语义捕获仅用于副作用的方法调用,而不需要返回类型(例如函数式 Java 的 Effect. 如果提供了非 void 返回类型,则将其忽略. 如果提供了 void 返回类型,它也会被忽略和接受。关键是语义必须以某种方式强制代理方法在另一个提取截获的代理方法调用的方法之前被调用。因为我们只对 side 感兴趣效果,候选方法很可能包括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 的整个目标是减少内部类实现的“垂直噪音”,我不是双括号初始化器的粉丝。无论提供什么建议,我都在寻找一种支持简洁的语义,尤其是单语句语义。

4

1 回答 1

1

我认为您永远无法将 a 强制void转换为表达式,特别是如果您不喜欢双括号破解。

您可以在 API 设计中遵循 Mockito 的示例。通常,您会像这样设置一个模拟:

when(mockedInstance.someMethod()).thenThrow(new IllegalArgumentException());

但是对于空白,您可以这样做:

doThrow(new IllegalArgumentException()).when(mockedInstance).someMethod();

同样,您可以枚举 的方法Effect<T>以使它们成为库的静态方法。

例如,如果Effect<T>doSomething()那么你会反转它,比如

doSomething().onEffectFor(proxyInstanceOfA).methodA();

但这假设相关方法Effect<T>本身不返回值。

如果这不是一个选项,并且您需要Effect<T>,则可以使其成为有状态的,如下所示:

VoidEffect<MyType> effect = effectForVoid(proxyOfMyClass);
effect.on().myVoidMethod();

Where VoidEffect<T>implements Effect<Void>,并on()返回传入的代理(或不同的代理)。然后你会想在你与之交互之前抛出一个IllegalStateExceptionif没有被调用。on()effect

于 2012-08-27T05:11:54.423 回答