我正在尝试为我正在从事的开源项目创建一个 API,但我在尝试扩展 API 的同时保持语义与当前 API 一致时遇到了障碍。我想要的是能够使用通用参数定义方法签名,该参数接受调用 any 方法签名的结果。 “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
。如果非空返回type 被提供,它被忽略。如果提供了 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 的整个目标是减少内部类实现的“垂直噪音”,我不喜欢双括号初始化器。无论提供什么建议,我都在寻找支持简洁的语义,尤其是单语句语义。
最佳答案
我认为你永远无法强制 void
变成一个表达式,特别是如果你不喜欢双括号 hack。
您可以在 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();
在哪里VoidEffect<T>
工具 Effect<Void>
, 和 on()
返回传入的代理(或不同的代理)。然后你会想要抛出一个 IllegalStateException
如果on()
在您与 effect
交互之前未被调用.
关于java - 接受void的通用参数类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12136381/