Java里面可以像JS那样写回调方法吗?

2020-12-21  本文已影响0人  程就人生

问题描述:

在某一个页面,有一个按钮a,点击按钮a,调用接口A,请求参数3个,返回参数5个;在另一个页面,有一个按钮b,点击按钮b,调用接口B,请求参数4个,返回参数5个;来自不同页面的两个按钮,看似不相关,请求参数不一样,但是在后台的业务逻辑处理上,却有百分之九十的代码是一样的,还有百分之十,是处理一个不同的类,在返回值上,也仅有这一个类不一样。

那么这样的接口该如何写呢?

解决方法一:
这是最笨的方法,A接口的业务逻辑单独处理;写完A接口,写B接口时,发现和A接口有百分之九十的相似,那好办,把A接口的代码拷贝一份,把不一样的地方改一改,OK了。

如果A、B接口分别由不同的人写时,就会出现两种风格的代码。A、B接口的业务逻辑处理是分开的,各自处理各自的,该公共的没公共。

这样的问题很明显,代码不够精简,后期维护成本高。

解决方法二:
把A、B接口业务处理逻辑一样的代码,提取出来,作为一个公共的方法调用,调用完公共的代码后,根据处理结果的返回值,再处理最后百分之十不一样的地方。

这样写的好处很明显,代码精简,后期维护成本低,代码更优质,而实际上是怎么处理的呢?

负责这两个接口的同事是同一位,他先写好了A接口,前端也调用成功;在准备写B接口时,发现和A接口大部分的业务逻辑是一样的,于是把A接口改了改,改成一个公共的方法,可以供A、B同时调用的方法,如果有接口C,也和A、B的情况类似,就可以直接写个简单的接口,调用这个公共方法,调用完这个公共方法,需要写的代码也就很少了。

那这位小伙伴使用的是解决方法二吗?

是解决方法二,又不是解决方法二,而是解决方法二升级的解决方法三。

解决方法三:

写过前端JS代码的小伙伴都知道,在处理完一个方法时,还可以传递方法名回调另一个方法。没错,这位小伙伴就想到了回调的处理方法,去处理最后百分之五的不同。

在Java里面可不可以这样写呢?

答案是可以的,两种写法任你选。

有那么一个注解:@FunctionalInterface,功能性接口,啥意思呢,先看看它的源码:

/*
 * <ul>
 * <li> The type is an interface type and not an annotation type, enum, or class.
 * <li> The annotated type satisfies the requirements of a functional interface.
 * </ul>
 *
 * <p>However, the compiler will treat any interface meeting the
 * definition of a functional interface as a functional interface
 * regardless of whether or not a {@code FunctionalInterface}
 * annotation is present on the interface declaration.
 *
 * @jls 4.3.2. The Class Object
 * @jls 9.8 Functional Interfaces
 * @jls 9.4.3 Interface Method Body
 * @since 1.8
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

示例代码:

/**
 * 定义了一个接口,用于传递回调方法
 * @author 程就人生
 * @date 2020年12月21日
 */
@FunctionalInterface
public interface Function<T> {

    T nextFunction(int i);  
}

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 测试代码
 * @author 程就人生
 * @date 2020年12月21日
 */
public class Test {

    
    /**
     * A接口,参数省略...
     * @return
     *
     */
    public static Map<String,Object> interfaceA(){
        Map<String, Integer> aa = new HashMap<String,Integer>();
        aa.put("aa", 100);
        //传递各自的业务类,提前把回调方法写好
        Function<Object> callbackFunction=(i)->{
            aa.put("aa", aa.get("aa").intValue() + i);
            System.out.println(i+"aaaa");
            return aa;
        };
        //调用公共方法时,把回调方法当作一个参数进行传递
        return commonFunction(callbackFunction);
    }
    
    /**
     * B接口,参数省略...
     * @return
     *
     */
    public static Map<String,Object> interfaceB(){
        //
        List<String> aa = new ArrayList<String>();
        aa.add("1");
        //传递各自的业务类,提前把回调方法写好
        Function<Object> callbackFunction=(i)->{
            aa.add(i+"");
            System.out.println(i+"bbbbb");
            return aa;
        };
        //调用公共方法时,把回调方法当作一个参数进行传递
        return commonFunction(callbackFunction);
    }
    //公共方法,其他参数已省略
    public static Map<String,Object> commonFunction(Function callbackFunction){
        
        //省略业务逻辑处理代码300行.....
        
        Object obj = callbackFunction.nextFunction(1111);
        
        Map<String,Object> map = new HashMap<String,Object>();
        //返回不一样参数
        map.put("object", obj);     
        return map;
    }
    
    public static void main(String[] argo){
        interfaceA();
        interfaceB();
    }
    
    /**
     * 也可以以内部接口的形式进行定义
     * @author 程就人生
     * @date 2020年12月21日 
     * @param <T>
     */
    /*public interface Function<T> {

        T nextFunction(int i);  
    }*/
}

测试结果:


在这个demo里,已经把很多业务逻辑省略了,只写了回调函数的使用,回调函数,先定义再使用,既可以使用内部接口,也可以使用@FunctionalInterface注解,这样保证了代码的完整性,是不是很简单呢?

上一篇下一篇

猜你喜欢

热点阅读