【问题标题】:Store and call method from a HashMap从 HashMap 存储和调用方法
【发布时间】:2017-11-14 13:35:02
【问题描述】:

我有 2 个文件:ImplementationProvider 和 CaseHandler。

实施提供者:

class ImplementationProvider {
    public void method1(Object[] params) {}
    public void method2(Object[] params) {}
    ...
    public void method100(Object[] params) {}
}

案例处理程序:

class CaseHandler {
    ImplementationProvider ip; // auto injected
    public void handle(String s, String param) {
        switch(s) {
            case USE_CASE_ONE: ip.method1(param); break;
            case USE_CASE_TWO: ip.method2(param); break;
            ...
        }
    }   
}

如何重构 CaseHandler 以便 USE_CASE 字符串是 HashMap 中的键,其中值将是方法?我遇到的主要问题是参数的传播。这里的其他答案建议使用接口,但是我需要在运行时提供参数。

【问题讨论】:

  • 你的 100 个方法的返回类型是什么?它应该是无效的吗?
  • @Eran 它们现在都是无效的(目前想不出它们不会出现的用例)
  • 您希望通过将方法放入哈希图中获得什么?绑定是否在运行时更改?我倾向于将 s 处理为有效的方法名称并使用反射,如果您必须对所有绑定进行编码,那么构建 hashmap 可能比 case 语句更难维护。
  • @PeteKirkham 减少 CaseHandler 中的代码,O(1) 搜索正确的方法。
  • 您的分析是否显示这是一个瓶颈?散列一个字符串需要处理它的所有字符,然后你有一个额外的重定向级别。开关也不必这样做(取决于优化编译器的能力,但 IIRC 优化仅适用于在许多情况下的 switch 语句,因为适合 CPU 缓存的线性搜索比导致结果的散列更快错过)。如果必须设置地图,代码总量会更大。

标签: java design-patterns refactoring


【解决方案1】:

这是我能想到的一种方式,使用Consumer功能接口:

Map<String,Consumer<Object[]>> methods = new HashMap<>();

methods.put (USE_CASE_ONE, param -> ip.method1(param));
methods.put (USE_CASE_TWO, param -> ip.method2(param));
...

public void handle(String s, String param) {
    methods.get(s).accept(new Object[]{param});
}

编辑:

如果你的方法需要两个参数,你可以使用BiConsumer接口:

Map<String,BiConsumer<String,List<String>>> methods = new HashMap<>();

methods.put (USE_CASE_ONE, (s,l) -> ip.method1(s,l));
methods.put (USE_CASE_TWO, (s,l) -> ip.method2(s,l));
...

public void handle(String s, String param) {
    methods.get(s).accept(someString,someListOfStrings);
}

【讨论】:

  • 在我的具体用例中,有 2 个参数,而不是只有一个(String 和 List)。接受这两个参数的正确语法是什么(或者我如何概括,因为我正在调用的方法可能需要 N 个参数)。使用 Object[],参数的类型为 Object[] 和 。 map.put("USE_CASE_ONE", (param_one, param_two) -> ip.method1(param_one, param_two));
  • @i712345 如果需要两个参数,请使用BiConsumer&lt;String,List&lt;String&gt;&gt; 而不是Consumer&lt;Object[]&gt;
  • 啊哈,我现在明白这个模式了。所以总的来说,如果我创建一个类来存储我的参数数据(因为我不知道我需要多少个参数)然后从一个对象访问我需要的那些会更好?
  • 您可以使用方法引用并将param -&gt; ip.method1(param)缩短为ip::method1
  • @markusk 没错,但有些方法没有使用第二个参数。
【解决方案2】:

如果您使用的是 Java 8,则可以利用 Consumer 功能接口来参数化地图的值。

例子:

private static Map<String, Consumer<String>> MAP = new HashMap<>();
static {
    MAP.put("USE_CASE_ONE", (s) -> {/*TODO something with param s*/});
    // etc.
}

...然后在其他地方:

public void handle(String key, String param) {
        // TODO check key exists
        MAP.get(key).accept(param);
}

这里发生的是,对于每个给定的键集条目,您将其映射到使用 String(您的 param)的函数。

然后,您在一行中调用给定参数上的Consumeraccept

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 2015-08-14
    • 2013-11-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    相关资源
    最近更新 更多