3

也许我在 C 中想了很多,但我没有看到如何在 java 中正确解决这个问题的解决方案。我收到来自服务器的响应,该响应发送如下字符串:

command params <xml...>

客户端接收该字符串并提取命令。现在我想调用一个知道如何处理命令的函数。在 C 方面,解决方案是显而易见的。我用命令名称和相关的函数指针实现了一个数组,所以我可以简单地遍历数组并调用函数。

有没有办法在 Java 上做到这一点?我不知道我可以根据名称调用函数。所以目前我看到以下选项:

  1. 做一系列if(command.euqals(COMMAND)
  2. 对于每个命令,我可以创建一个单独的对象,我可以将其存储在一个数组中(非常混乱)。
  3. 使用反射,所以我可以有一个函数名称与命令名称的映射。

还有其他选择吗?

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

4

4 回答 4

2

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

有一个标准的接口:

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());

然后你可以有一个方法来处理通用命令(验证和数组修剪省略):

public void handleCommand(String[] command) {
    executors.get(command[0]).execute(command);
}
于 2013-08-07T10:14:45.887 回答
1

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

不要害怕创建课程!它可能会使您的代码开始时更加冗长,但是编写一个类并且永远不必再担心它比使用switchor做同样的事情要容易得多if ... else if ...。如果您的命令变得比单个方法更复杂(也许toString()undo()...),您会越来越高兴您使用多态性而不是条件。

于 2013-08-07T10:10:07.750 回答
0

如果您只想拥有一个文件,可以使用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);
于 2013-08-07T11:00:01.007 回答
0

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

下面是我为了展示这个技巧而编写的代码示例。我的示例只为一个命令提供一个函数,但如果需要,它可以很容易地扩展到返回的一堆函数(因此包含可以使用的 Guava Mutlimap 类型)......我返回一个 Optional 所以当一个命令不匹配,它“安全地”返回一个空值;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;
        }
    };
}

}

为了让生活更轻松,我包含了 Domain 类代码:

/**
 * Created by beezerbutt on 06/04/2017.
 */
public class Contact implements Organization {
}
public class ContactUnit implements Organization {
}
public interface Organization {
}

下面是我运行的 Spock 测试的快照,以证明代码有效: 在此处输入图像描述

于 2017-04-16T11:55:30.843 回答