一.前言
public interface Way {
void solve2();
void solve1();
void solve3();
void solve4();
}
/**
* 其实我们真正需要该接口的方法只有solve2,但是接口的其他三个接口还得重写
* 然后给个空实现,产生了无用代码堆积
*/Way way = new Way() {
@Override
public void solve2() {
System.out.println("child solve2");
}
@Override
public void solve1() {
}
@Override
public void solve3() {
}
@Override
public void solve4() {
}
}
本篇文章主要是从Java和Kotlin的角度分别阐述怎么解决该痛点
二.Java优化接口实现
- 接口属于系统API或第三方库API定义
以上面的Way为例,假如该接口是系统提供的,我们可以通过抽象类方式作为业务代码实现和系统接口的一个桥梁
定义一个抽象类,空实现Way接口的全部方法:
public abstract class WayAdapter implements Way {
@Override
public void solve2() {
}
@Override
public void solve1() {
}
@Override
public void solve3() {
}
@Override
public void solve4() {
}
}
这样如果业务中再需要使用这个系统接口Way的时候,我们不实现Way直接继承上面类WayAdapter,有选择性重写我们需要的方法,而无需额外处理其他非必须方法
@Test
public void main() {
Way way = new WayAdapter() {
@Override
public void solve2() {
}
};
}
Animation动画监听类AnimatorListenerAdapter就基于此
- 接口属于自身业务层定义
我们直接利用java8的default关键字来修改接口部分方法的定义方式:default在接口中修饰的方法可以直接在接口中就给出个空实现,子类不需要这个方法也不需要额外的重写
public interface Way {
void solve2();
default void solve1() {
}
default void solve3() {
}
default void solve4() {
}
}
如果Way接口强制要求solve2子类必须重写,其他方法可选,那我们直接给可选的方法使用default修饰给个空实现即可
@Test
public void main() {
Way way = new Way() {
@Override
public void solve2() {
}
};
}
Lifecycle的DefaultLifecycleObserve就基于此
三.Kotlin优化接口实现
- 接口属于系统API或第三方库API定义
这种情况Kotlin有两种解决方式:
- 和上面java一样通过一个中间抽象类解决
interface Color {
fun alpha()
fun result()
fun process()
}
abstract class ColorAdapter: Color {
override fun alpha() {
}
override fun result() {
}
override fun process() {
}
}
- 通过Kotlin DSL的语法特性解决
//获取一个Color接口类型的对象
fun obtainColor(block: ColorAdapter.() -> Unit): Color {
return ColorAdapter().apply(block)
}
class ColorAdapter : Color {
private var alpha: (() -> Unit)? = null
private var result: (() -> Unit)? = null
private var process: (() -> Unit)? = null
fun setAlpha(block: () -> Unit) {
alpha = block
}
fun setResult(block: () -> Unit) {
result = block
}
fun setProcess(block: () -> Unit) {
process = block
}
override fun alpha() {
alpha?.invoke()
}
override fun result() {
result?.invoke()
}
override fun process() {
process?.invoke()
}
}
在业务需要的地方就可以如下这样使用:
//根据业务需要调用需要的setResult或setResult()或setProcess()方法
val color: Color = obtainColor {
setResult {
//todo 实现具体的代码逻辑
}
}
- 接口属于自身业务层定义
这种方式实现也基本和java的方式一样,区别在于kotlin不用加default
interface Color {
fun alpha() {
}
fun result() {
}
fun process()
}
使用:
val color2: Color = object : Color {
override fun process() {
}
}
四.彩蛋(题外话)
Kotlin下如果需要定义一个函数式接口(只包含一个方法的接口),Kotlin有两种方式:
- 如果想要实现SAM转换,则kotlin接口定义的时候需要前面加个fun关键字(kotlin1.4才开始有)
fun interface Tree {
fun num()
}
- 直接利用Kotlin特有的函数类型,而无需定义接口:
var listen: ((View) -> Unit)? = null