问题描述:
在某一个页面,有一个按钮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注解,这样保证了代码的完整性,是不是很简单呢?
网友评论