日常调戏Java:方法的分步调用

日常调戏Java:方法的分步调用

起因

最近碰到好几起开发人员被API/框架绑架的情形,比如想调用某个第三方库的API,而部分参数还没有准备好,然后拐着弯的写功能来确保调用时这些参数都同时准备好。这样就导致了即便这个API不是侵入式的,但是开发人员按照API来设计代码,使得达到了侵入式的后果…先同情下这样的朋友。

由此事件联想到了好几年前学习函数式编程时所产生的冲击,尤其是柯里化(Currying)。柯里化可以让多参数函数在调用时每次调用传递一个参数,例如以下的javascript代码:

//正常的调用
test(1, 2, 3, 4)

//柯里化调用1
test(1)(2)(3)(4)

//柯里化调用2
let fun = test(1)(2)
....//中间执行若干操作
fun(3)(4)

但是,为现有的方法添加柯里化风格的支持还是有一定工作量的。当然,这类问题用适配器模式和建造者模式来解决也是不错的方法,但是开发一些临时的建造者也挺麻烦(手敲累,会多出很多类)。这篇文档就提供一种简单、通用且有趣的方式来处理这类问题。

经过

代码很少,直接上代码。(懒得看的,直接到下方看结果)

/* 函数式接口,这里只考虑5个参数以下且有返回值的调用,10个参数类似,无返回值就用Consumer */
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);

    @FunctionalInterface
    interface BiFunction<A, B, V> {
        V apply(A a, B b);
    }

    @FunctionalInterface
    interface Function3<A, B, C, V>{
        V apply(A a, B b, C c);
    }

    @FunctionalInterface
    interface Function4<A, B, C, D, V>{
        V apply(A a, B b, C c, D d);
    }

    @FunctionalInterface
    interface Function5<A, B, C, D, E, V>{
        V apply(A a, B b, C c, D d, E e);
    }
}

/* 核心类,30行代码把方法包装成柯里化风格,Result只是用来处理异常用的(参考另一篇文章),不需要的可以直接去掉 */
public class Invoker<T, R> {
    private final Function<T, R> function;

    public Invoker(Function<T, R> function) {
        this.function = function;
    }

    public static <A, V> Invoker<A, Result<V>> invoke(Function<A, V> function) {
        return new Invoker<>((A a) -> Result.from(() -> function.apply(a)));
    }

    public static <A, B, V> Invoker<A, Invoker<B, Result<V>>> invoke(BiFunction<A, B, V> function) {
        return new Invoker<>((A a) -> invoke(b -> function.apply(a, b)));
    }

    public static <A, B, C, V> Invoker<A, Invoker<B, Invoker<C, Result<V>>>> invoke(Function.Function3<A, B, C, V> function) {
        return new Invoker<>((A a) -> invoke((B b, C c) -> function.apply(a, b, c)));
    }

    public static <A, B, C, D, V> Invoker<A, Invoker<B, Invoker<C, Invoker<D, Result<V>>>>> invoke(Function.Function4<A, B, C, D, V> function) {
        return new Invoker<>((A a) -> invoke((B b, C c, D d) -> function.apply(a, b, c, d)));
    }

    public static <A, B, C, D, E, V> Invoker<A, Invoker<B, Invoker<C, Invoker<D, Invoker<E, Result<V>>>>>> invoke(Function.Function5<A, B, C, D, E, V> function) {
        return new Invoker<>((A a) -> invoke((B b, C c, D d, E e) -> function.apply(a, b, c, d, e)));
    }

    public R apply(T t) {
        return function.apply(t);
    }
}

结果

下面是调用示例:

public class Test{
    private static int test1(String i) {
        return Integer.parseInt(i);
    }

    private static String test2(int i, String s) {
        return s + " => " + i;
    }

    private static String test3(int i, int j, String s) {
        return s + " -> " + i + " - " + j;
    }

    private static String test4(int i, int j, String s, Object o) {
        return s + " -> " + i + " - " + j + " - " + o;
    }

    public static void main(String[] args){
        //单参数调用
        int i = Invoker.invoke(Test::test1).apply("1").get();
        //2个参数的调用
        String s = Invoker.invoke(Test::test2).apply(1).apply("asdf").get();
        //3个参数的调用
        String s1 = Invoker.invoke(Test::test3).apply(1).apply(2).apply("").get();
        //4个参数的调用
        String ss = Invoker.invoke(Test::test4).apply(1).apply(2).apply(null).apply(new boolean[1]).get();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值