首页 > 解决方案 > Java 方法接受不同的功能接口类型 - 可能吗?

问题描述

首先,抱歉标题不好,但我发现用一句话概括我的问题有点困难......

我们的软件中有一些我很不满意的代码。它是这样的:

    @FunctionalInterface
    public interface OneArgCall<T, U, A> {
        T execute(U u, A arg);
    }

    @FunctionalInterface
    public interface TwoArgCall<T, U, A, B> {
        T execute(U u, A arg, B arg2);
    }

    public <T, U, A, B> T execCall(String x, Class<U> c, OneArgCall<T, U, A> call, A arg) {
        U u = doSomething(x, c);
        try {
            return call.execute(u, arg);
        } catch (SomeException se) {
           handleSe(se);
        } catch (SomeOtherException soe) {
           handleSoe(soe);
    }
    
    public <T, U, A, B> T execCall(String x, Class<P> c, TwoArgCall<T, U, A, B> call, A arg, B arg2) {
        U u = doSomething(x, c);
        try {
            return call.execute(u, arg, arg2);
        } catch (SomeException se) {
           handleSe(se);
        } catch (SomeOtherException soe) {
           handleSoe(soe);
    }

即 execCall 方法是相同的,除了作为第三个参数传递的功能接口(当然还有那个接口的参数列表)。现在,我仍然可以忍受,但是还有更多这些方法(想象一下 ThreeArgCall、FourArgCall ......)——这就是它变得难以忍受的地方。

所以,以所有 DRY 的名义:你将如何清理这段代码?我想像T execCall(String x, Class<U> c, SOMETHING, SOMETHING_ELSE)SOMETHING 可以是 OneArgCall、TwoArgCall... 接口中的任何一个,而 SOMETHING_ELSE 代表参数列表(?)。

这完全可以做到吗?还是有其他方法可以重构此代码以减少重复性?

标签: javagenericslambdadryfunctional-interface

解决方案


您实际上并不需要所有这些接口。您不需要接受任何额外的方法参数。所有这些都可以由调用者使用 lambda 语法来处理。

这是您唯一需要的方法:

public <T, U> T execCall(String x, Class<U> c, Function<U, T> call) {
    U u = doSomething(x, c);
    try {
        return call.apply(u);
    } catch (SomeException se) {
       handleSe(se);
    } catch (SomeOtherException soe) {
       handleSoe(soe);
    }
}

现在,假设您有一个方法,该方法需要使用多个参数,它是execCall()如何工作的?

public Foo someMethodCall(Bar bar, Arg1 a1, Arg2 a2) { .... }

Arg1 a1 = ...;
Arg2 a2 = ...;
String x = ...;
Bar b = execCall(x, Bar.class, (u) -> someMethodCall(u, a1, a2));

使用 lambda 语法,您可以将 3 参数方法“调整”到一个 argFunction接口。这是使用“部分应用程序”的函数式编程概念。


推荐阅读