Java 作为返回参数的Void值
我有这个界面:Java 作为返回参数的Void值,java,command,adapter,Java,Command,Adapter,我有这个界面: public interface Command<T> { T execute(String... args); } 保持界面原样:这就是为什么标准库中存在Void。只要调用该命令的内容希望返回空值,就可以了 是的,null是唯一可以为Void返回的值 2017年更新 在过去的几年中,我一直避免将Void作为返回类型,除非涉及反射。我使用了一种不同的模式,我认为它更明确,并且避免了空值。也就是说,我有一个success类型,我称之为Ok,它为所有命令(如OP
public interface Command<T> {
T execute(String... args);
}
保持界面原样:这就是为什么标准库中存在Void。只要调用该命令的内容希望返回空值,就可以了 是的,null是唯一可以为Void返回的值 2017年更新 在过去的几年中,我一直避免将
Void
作为返回类型,除非涉及反射。我使用了一种不同的模式,我认为它更明确,并且避免了空值。也就是说,我有一个success类型,我称之为Ok
,它为所有命令(如OP)返回。这对我的团队来说非常有效,并且已经推广到其他团队中使用
public enum Ok { OK; }
public class SideEffectCommand implements Command<Ok> {
@Override
public Ok execute(String... args) {
...
return Ok.OK; // I typically static import Ok.OK;
}
public enum Ok{Ok;}
公共类SideEffectCommand实现该命令{
@凌驾
公共Ok执行(字符串…参数){
...
return Ok.Ok;//我通常静态导入Ok.Ok;
}
在您的示例中,有趣的是参数化类型的使用
interface Command<T> {
public T execute(T someObject);
}
接口命令{
公共T执行(T someObject);
}
在您的例子中,您只有T
作为返回值。然而,在这种情况下使用Void是一个很好的解决方案。返回值应该是null
,这个问题并不常见,但也不罕见……我想我在不久前看到过关于这个问题的讨论,关于不返回任何内容的可调用项
我同意其他海报上的说法,这是一个很好的解决方案,比使用Object或其他虚拟占位符要好得多。我会坚持显式使用
Void
。在不涉及其他类的情况下,很容易看到正在发生的事情。如果您可以用Void
覆盖返回,那就太好了(和Integer
和int
等),但这不是优先考虑的问题。这不是常见问题。您需要解决的问题是对界面的期望。您将非副作用界面的行为与允许副作用的界面相结合
考虑这一点:
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());
}
}
}
因为现在有办法知道实现是否真的有对象或是空的。对于特定的情况,您肯定会知道,因为您对实现很熟悉。但是一旦您开始聚合它们,或者它们超出了您的编码范围(用作库、将来的维护等)空问题将出现
接下来,我尝试了这个:
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.");
}
}
但这说明了问题的根源,您的客户端代码开始需要了解实现细节。接口应该在可能的情况下帮助隔离代码依赖关系。此时添加它们似乎是一种糟糕的设计
归根结底,您需要使用一种设计,该设计明确了您期望命令何时会产生副作用,并考虑如何处理一组命令,即未知命令的数组
这可能是一个例子。在我看来很好。正如其他人所说,Void
最初是为反射机制设计的,但现在它在泛型中经常用于描述像您这样的情况
更好的是:谷歌,在他们的GWT框架中,在他们的示例中使用了相同的想法来返回一个空回调()。我说:如果谷歌这样做了,它必须至少是好的。:)这是一个多世界的最佳实现
// Generic interface for when a client doesn't care
// about the return value of a command.
public interface Command {
// The interfaces themselves take a String[] rather
// than a String... argument, because otherwise the
// implementation of AbstractCommand<T> would be
// more complicated.
public void execute(String[] arguments);
}
// Interface for clients that do need to use the
// return value of a command.
public interface ValuedCommand<T> extends Command {
public T evaluate(String[] arguments);
}
// Optional, but useful if most of your commands are ValuedCommands.
public abstract class AbstractCommand<T> implements ValuedCommand<T> {
public void execute(String[] arguments) {
evaluate(arguments);
}
}
// Singleton class with utility methods.
public class Commands {
private Commands() {} // Singleton class.
// These are useful if you like the vararg calling style.
public static void execute(Command cmd, String... arguments) {
cmd.execute(arguments);
}
public static <T> void execute(ValuedCommand<T> cmd, String... arguments) {
return cmd.evaluate(arguments);
}
// Useful if you have code that requires a ValuedCommand<?>
// but you only have a plain Command.
public static ValuedCommand<?> asValuedCommand(Command cmd) {
return new VoidCommand(cmd);
}
private static class VoidCommand extends AbstractCommand<Void> {
private final Command cmd;
public VoidCommand(Command actual) {
cmd = actual;
}
public Void evaluate(String[] arguments) {
cmd.execute(arguments);
return null;
}
}
}
//当客户端不关心时的通用接口
//关于命令的返回值。
公共接口命令{
//接口本身采用字符串[],而不是
//而不是字符串…参数,因为
//AbstractCommand的实现将是
//更复杂。
public void execute(字符串[]参数);
}
//为确实需要使用
//命令的返回值。
公共接口ValuedCommand extends命令{
公共T求值(字符串[]参数);
}
//可选,但如果大多数命令都是ValuedCommand,则很有用。
公共抽象类AbstractCommand实现ValuedCommand{
public void execute(字符串[]参数){
评价(论据);
}
}
//带有实用程序方法的Singleton类。
公共类命令{
private Commands(){}//Singleton类。
//如果您喜欢vararg调用样式,那么这些都很有用。
公共静态void execute(命令cmd、字符串…参数){
cmd.execute(参数);
}
公共静态void execute(ValuedCommand cmd,String…参数){
返回cmd.evaluate(参数);
}
//如果您有需要ValuedCommand的代码,则非常有用
//但你只有一个简单的命令。
公共静态值命令asValuedCommand(命令cmd){
返回新的命令(cmd);
}
私有静态类VoidCommand扩展了AbstractCommand{
私人最终命令cmd;
公共命令(实际命令){
cmd=实际值;
}
公共Void求值(字符串[]参数){
cmd.execute(参数);
返回null;
}
}
}
通过此实现,如果客户机不关心返回值,则可以使用命令
;如果客户机需要返回特定值的命令,则可以使用值命令
关于不直接使用Void
的唯一原因是所有难看的返回null;
语句,您将被迫插入这些语句。如果没有如下界面,该怎么办
public interface Command<T> {
T execute(String... args);
}
公共接口命令{
T执行(字符串…参数);
}
相反,你有:
public interface Command<T> {
void execute(String... args);
T getResult();
bool hasResult();
}
公共接口命令{
无效执行(字符串…参数);
T getResult();
bool hasResult();
}
然后打电话的人会做:
public void doSomething(Command<?> cmd) {
cmd.execute(args);
if(cmd.hasResult()) {
// ... do something with cmd.getResult() ...
}
}
public void doSomething(命令cmd){
cmd.execute(args);
if(cmd.hasResult()){
//…使用cmd.getResult()执行某些操作。。。
}
}
如果愿意,还可以创建一个扩展命令的接口VoidCommmand
这
// Generic interface for when a client doesn't care
// about the return value of a command.
public interface Command {
// The interfaces themselves take a String[] rather
// than a String... argument, because otherwise the
// implementation of AbstractCommand<T> would be
// more complicated.
public void execute(String[] arguments);
}
// Interface for clients that do need to use the
// return value of a command.
public interface ValuedCommand<T> extends Command {
public T evaluate(String[] arguments);
}
// Optional, but useful if most of your commands are ValuedCommands.
public abstract class AbstractCommand<T> implements ValuedCommand<T> {
public void execute(String[] arguments) {
evaluate(arguments);
}
}
// Singleton class with utility methods.
public class Commands {
private Commands() {} // Singleton class.
// These are useful if you like the vararg calling style.
public static void execute(Command cmd, String... arguments) {
cmd.execute(arguments);
}
public static <T> void execute(ValuedCommand<T> cmd, String... arguments) {
return cmd.evaluate(arguments);
}
// Useful if you have code that requires a ValuedCommand<?>
// but you only have a plain Command.
public static ValuedCommand<?> asValuedCommand(Command cmd) {
return new VoidCommand(cmd);
}
private static class VoidCommand extends AbstractCommand<Void> {
private final Command cmd;
public VoidCommand(Command actual) {
cmd = actual;
}
public Void evaluate(String[] arguments) {
cmd.execute(arguments);
return null;
}
}
}
public interface Command<T> {
T execute(String... args);
}
public interface Command<T> {
void execute(String... args);
T getResult();
bool hasResult();
}
public void doSomething(Command<?> cmd) {
cmd.execute(args);
if(cmd.hasResult()) {
// ... do something with cmd.getResult() ...
}
}