这不是一个常见的问题。您需要解决的问题是对界面的期望。您正在将非副作用接口的行为与允许副作用的接口相结合。
考虑一下:
public class CommandMonitor {
public static void main(String[] args) {
Command<?> sec = new SideEffectCommand();
reportResults(sec);
}
public static void reportResults(Command<?> cmd){
final Object results = cmd.execute("arg");
if (results != null ) {
System.out.println(results.getClass());
}
}
}
使用<Void>
作为模板类型没有任何问题,但允许它与“命令<T>
”的实现混合意味着接口的某些客户端可能不会期望一个 void 结果。在不更改接口的情况下,您已经允许实现创建意外结果。
当我们使用 Collection 类传递数据集时,我的团队同意永远不会返回 null,即使它在语法上很好。问题是使用返回值的类必须经常检查 void 以防止 NPE。使用上面的代码,你会在任何地方看到这个:
if (results != null ){
因为现在有办法知道实现是否真的有一个对象或为空。对于特定情况,您肯定会知道,因为您熟悉实现。但是,一旦您开始聚合它们或它们超出您的编码范围(用作库,未来维护等),空问题就会出现。
接下来,我尝试了这个:
public class SideEffectCommand implements Command<String> {
@Override
public String execute(String... args) {
return "Side Effect";
}
}
public class NoSideEffectCommand implements Command<Void>{
@Override
public Void execute(String... args) {
return null;
}
}
public class CommandMonitor {
public static void main(String[] args) {
Command<?> sec = new SideEffectCommand();
Command<?> nsec = new NoSideEffectCommand();
reportResults(sec.execute("args"));
reportResults(nsec.execute("args")); //Problem Child
}
public static void reportResults(Object results){
System.out.println(results.getClass());
}
public static void reportResults(Void results){
System.out.println("Got nothing for you.");
}
}
重载不起作用,因为对 reportResults 的第二次调用仍然调用期望对象的版本(当然)。我打算改成
public static void reportResults(String results){
但这说明了问题的根源,您的客户端代码开始必须了解实现细节。接口应该在可能的情况下帮助隔离代码依赖关系。在这一点上添加它们似乎是糟糕的设计。
最重要的是,您需要使用一种设计,当您期望命令具有副作用时清楚地表明您将如何处理一组命令,即一组未知命令。
这可能是抽象泄漏的情况。