一.前言

平常我们可能面对这样一个场景:系统的某个接口有很多方法,而我们业务需要实现这个接口,真正需要的只有该接口的几个方法而已,但是又不得不重写实现该接口其他无用的方法,以至于产生了大量无用代码堆积,比如:

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() {
    }
}

本篇文章主要是从JavaKotlkotlin和javain的角度分别阐述怎么解决该痛点

二.Java优化接口实现

  1. 接口属于系统API或第三方库API定义

以上面的动画片少儿小猪佩奇Way为例,假如该接口是系统提供appreciate的,我们可以通过抽象类方式作为业务代码实现和系统接口的一个桥梁

定义一个抽象类,空实现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() {
        }
    };
}

Animationjava语言动画监听类AnimatorListenerAdapter就基于此

  1. 接口属于自身业务层定义

我们直接利用java8的default关键字来修改接口部分方法的定义方式:default在接口中修饰的方法可以直接在接口中就给出个空实现,子类不需要这个方法也不需要额外的重写

public interface Way {
   void solve2();
   default void solve1() {
   }
   default void solve3() {
   }
   default void solve4() {
   }
}

如果Way接口强制要求sol动画专业ve2子类必须重写,其他方法可选,那我们直接给可选的方法使用default修饰给个空实现即可

@Test
public void main() {
    Way way = new Way() {
        @Override
        public void solve2() {
        }
    };
}

Lifecycle的DefaultLifecjava语言ycleObserve就基于此

三.Kotlin优化接口实现

  1. 接口属于系统API或第三方库API定义

这种情况Koappointmenttlin有两种解决方式:

  • 和上面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 实现具体的代码逻辑
    }
}
  1. 接口属于自身业务层定义

这种方式实现也基本和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.appstore4才开始有)
fun interface Tree {
    fun num()
}
  • 直接利用Kotlin特有的函数类型,而无需定义接口:

var listen: ((View) -> Unit)? = null