接口使用额外重写的无关方法太多?优化它

一.前言

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

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优化接口实现

  1. 接口属于系统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就基于此

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

我们直接利用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优化接口实现

  1. 接口属于系统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 实现具体的代码逻辑
    }
}
复制代码
  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.4才开始有)
fun interface Tree {
    fun num()
}
复制代码
  • 直接利用Kotlin特有的函数类型,而无需定义接口:

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

Guess you like

Origin juejin.im/post/7064201315487842318