Java中的函数数组?

Java中的函数数组?,java,jump-table,Java,Jump Table,也许我在C语言中想得太多了,但我没有看到一个解决方案,如何在java中正确地解决这个问题。 我从服务器收到一个响应,该响应发送一个字符串,如下所示: command params <xml...> 命令参数 客户端接收该字符串并提取命令。现在我想调用一个知道如何处理命令的函数。在C方面,解决方案是显而易见的。我用命令名和相关函数点实现了一个数组,因此我可以简单地循环数组并调用函数 在Java上也有这样做的方法吗?我不知道是否可以根据名称调用函数。因此,目前我看到以下选项: 执行一

也许我在C语言中想得太多了,但我没有看到一个解决方案,如何在java中正确地解决这个问题。 我从服务器收到一个响应,该响应发送一个字符串,如下所示:

command params <xml...>
命令参数
客户端接收该字符串并提取命令。现在我想调用一个知道如何处理命令的函数。在C方面,解决方案是显而易见的。我用命令名和相关函数点实现了一个数组,因此我可以简单地循环数组并调用函数

在Java上也有这样做的方法吗?我不知道是否可以根据名称调用函数。因此,目前我看到以下选项:

  • 执行一系列的
    if(command.euqals(command)
  • 对于每个命令,我可以创建一个单独的对象,并将其存储在一个数组中(非常混乱)
  • 使用反射,这样我就可以有一个带有函数名和命令名的映射
  • 还有其他选择吗


    if语句不是最好的IMO,但至少它允许编译器错误和类型检查。使用反射至少更优雅,因为我可以更容易地循环和扩展它,但当然,这意味着如果我键入错误的名称,我只能看到运行时错误。

    你的第二个想法是惯用的。使用
    映射来存储command名称和相应的代码,然后
    commands.get(commandName).run()
    执行一个命令


    不要害怕创建类!这可能会让你的代码一开始就更加冗长,但是编写一个类和不再担心它要比使用
    开关
    if…else if…
    做同样的事情容易得多。如果你的命令比单个方法更复杂(可能
    toString()
    undo()
    …),您会越来越高兴您使用了多态性而不是条件。

    我过去曾使用以下方法解决过此类问题,它可能适用于您的情况:

    具有标准界面:

    public interface Executable {
        public String getCommandName();
        public void execute(String[] params, String xml);
    }
    
    和x实现的数量:

    public class SaveExecutable implements Executable {
        private static final String COMMAND_NAME = "SAVE";
        public String getCommandName() {
            return COMMAND_NAME;
        }
    
        public void execute(String[] params, String xml) {
             ...
        }
    }
    
    然后将实现存储在HashMap中进行查找:

    HashMap<String, Executor> executors = new HashMap<>();
    executors.put("SAVE", new SaveExecutable());
    

    如果只想有一个文件,可以使用
    enum
    创建

    试着这样做:

        public class Command {
    
          public enum CommandName {
    
            UNDO,
            PRINT,
            RUN
          }
    
          public static void execute(String command, String[] params, String xml) {
            try {
              CommandName cname = CommandName.valueOf(command);
    
              switch (cname) {
                case UNDO:
                   undo (params, xml);
                  break;
                case PRINT:
                  //
                  break;
              }
            } catch (IllegalArgumentException iae) {
              // Unknown command
            }
          }
    
          public static void undo (String[] params, String xml) {
             // ....
          }
        }
    
    运行以下命令:

        Command.execute(command, params, xml);
    

    我最近看到一个函数技巧,虽然很简单,但非常有效:“用另一个函数包装”一个函数或一组函数

    下面是我为展示这一技巧而编写的代码示例。 我的示例只为一个命令提供一个函数,但如果需要,它可以很容易地扩展为返回的一组函数(因此包含可以使用的Guava Mutlimap类型)…我返回一个可选的,因此当命令不匹配时,它“安全地”返回null;Contact和ContacUnit都是域类型,它们都扩展了一个组织类型……这样下面的代码就有意义了

    package com.xxx.component;
    
    import com.google.common.collect.ArrayListMultimap;
    import com.google.common.collect.Multimap;
    import com.xxx.domain.Contact;
    import com.xxx.domain.ContactUnit;
    import com.xxx.domain.Organization;
    
    import java.util.Optional;
    import java.util.function.Function;
    
    /**
     * This serves up the functions used for the domain
     * to validate itself.
     * Created by beezerbutt on 06/04/2017.
     */
    public class MapSetDomainFunctionFactory {
    
        public static final Function<String, Optional<Organization>> toContactFromCwid = s-> Optional.ofNullable(s).map(Contact::new);
        public static final Function<String, Optional<Organization>> toContactUnitFromKey = s-> Optional.ofNullable(s).map(ContactUnit::new);
    
        public static final Function<String, Function<String, Optional<Organization>>> commandToFunctions = command -> {
            if (command.equalsIgnoreCase("toContactFromCwid")) {
                return MapSetDomainFunctionFactory.toContactFromCwid;
            } else {
                return null;
            }
        };
    }
    
    下面是我为证明代码有效而运行的Spock测试的快照:

    我觉得有点混乱,因为我必须创建很多类来执行一个任务,它甚至不能自己执行,相反它必须更新GUI等等。另一方面,也许这不是一个坏主意,我必须看看它对GUI代码有什么影响。我一点也不认为这是混乱的;它是pol的基石ymorphism!我越是考虑这种方法,我就越喜欢它。我最初的想法是我会有数百个小类,但在重新考虑参数后,它并没有那么糟糕,它肯定有你提到的优点。现在你可以创建匿名类就更好了。
    new Command(){run(){/*process command*/}
    -这可以是一个
    command
    数组,其中它是一个接口类。请记住,Java枚举可以有方法-您可以声明一个抽象
    doExecute
    ,而不是
    开关
    只需执行
    cname.doExecute()
    package com.xxx.component;
    
    import com.google.common.collect.ArrayListMultimap;
    import com.google.common.collect.Multimap;
    import com.xxx.domain.Contact;
    import com.xxx.domain.ContactUnit;
    import com.xxx.domain.Organization;
    
    import java.util.Optional;
    import java.util.function.Function;
    
    /**
     * This serves up the functions used for the domain
     * to validate itself.
     * Created by beezerbutt on 06/04/2017.
     */
    public class MapSetDomainFunctionFactory {
    
        public static final Function<String, Optional<Organization>> toContactFromCwid = s-> Optional.ofNullable(s).map(Contact::new);
        public static final Function<String, Optional<Organization>> toContactUnitFromKey = s-> Optional.ofNullable(s).map(ContactUnit::new);
    
        public static final Function<String, Function<String, Optional<Organization>>> commandToFunctions = command -> {
            if (command.equalsIgnoreCase("toContactFromCwid")) {
                return MapSetDomainFunctionFactory.toContactFromCwid;
            } else {
                return null;
            }
        };
    }
    
    /**
     * Created by beezerbutt on 06/04/2017.
     */
    public class Contact implements Organization {
    }
    public class ContactUnit implements Organization {
    }
    public interface Organization {
    }