JDK8漫谈——加强接口

解决什么问题

  • 向下兼容。添加方法,全部的实现类必须实现此方法,不然会编译报错。这意味着每一次的接口升级都会伤筋动骨。可是这是一把双刃剑必定要把握好场景,不要滥用。
  • 类爆炸。使用时,须要辅助类。即要记忆接口可能还须要记忆辅助类。
  • 内置行为。使用时,须要关注外部的过程性的处理逻辑。好比:循环,排序,过滤,转换类型,取默认值等。

背后思想

  • 封装。经过封装的思惟,把细节封装成方法。经过服务的调用解决代码复用和关注点过高的问题。
  • 兼容性。不少软件一升级就得从新学一遍~~

内容介绍

组成部分

接口一直不断在加强,可是整体来讲,仍是只放抽象的内容,不放实例化相关的内容。java

  • 公有常量。
  • 公有方法。没有具体实现,通常不须要写public,默认的就是。
  • 私有方法(JDK9)
  • 静态方法。有具体实现,和静态方法调用一直。
  • 默认方法。有具体实现,能够被实现类重写而且直接调用。
public interface Powerable {
    /**
     * 公有常量
     */
    String NAME = "me";

    /**
     * 公有方法
     */
    void print();

    /**
     * 静态方法
     * @param name
     */
    static void cry(String name){
        System.out.print(name+"is crying");
    }

    /**
     * 默认方法
     */
    default void fly(){
        System.out.print(Powerable.NAME+"can fly");
    }

}

注意事项工具

  • 不容许有成员变量。

方法优先级

  • 类优先于接口。若是一个子类继承父类和接口有相同的方法实现。那么子类继承父类方法
  • 子类中的方法优先于父类中方法
  • 若是以上条件都不知足,则必须显示覆盖/实现其方法,或者声明成abstract

实战

最佳实践

减小类爆炸

常常使用到的抽象逻辑封装成默认方法,减小辅助类类。.net

@Test
public void test_default(){
    Map<String,String> map = new HashMap();
    String defaultIntro = "";

    //方案一,须要使用工具类
    String utilsIntro = MapUtils.getorDefault(map, "intro", defaultIntro);
    System.out.println(utilsIntro);

    //方案二,无需使用工具类
    System.out.print(map.getOrDefault("intro", defaultIntro));
}
  • 减小须要思考多份职责,须要关注接口还须要关注类。
  • 减小类,提供代码优雅度。

内置处理

细节封装成默认方法,减小关注度和出错率,提高服务的稳定和优雅性code

public void test_default_encapsulation() {
    Map<String, String> map = new HashMap<>();
    //方案一:经过显式的循环,感知的细节太多。须要显示感知类型,还须要关注Entry对象以及getKey和getValue
    for (Map.Entry entry : map.entrySet()) {
        System.out.println(entry.getKey() + "," + entry.getValue());
    }
    //方案二:经过显式的循环,感知的细节太多。须要显示感知类型,还须要key以及map获取
    for (String key : map.keySet()) {
        System.out.println(key + "," + map.get(key));
    }
    //方案三:内置方法,不用考虑循环,不须要考取取值细节
    map.forEach((key, value) -> {
        System.out.println(key + "," + value);
    });
}
  • 封装细节,把细节变成方法。
  • 改变思惟方式,从面向细节到面向服务。原来是:循环map,经过什么类型获取key,value,执行任务,任务里使用key,value;如今是:map循环执行任务,任务里使用key,value。

最佳反例

放具体的实例

好比把原来的工厂放到如今的接口默认方法里。对象

default Powerable run(int type) {
    switch (type) {
        case 1:
            return new Person();
        default:
            return null;
    }

}
  • 接口不稳定,会不断变修改。
  • 接口依赖实现,本末倒置。

使用default来完成多态

子类重写父类的default方法blog

  • 关注点过高,接口职责不清晰。须要看一下接口有哪里default,而后还须要判断哪些是须要重写的,哪些只能能用逻辑。

再次思考

  • 接口是否变成万能类,职责愈来愈多,愈来愈重?
  • 何时使用抽象类,何时使用接口?
  • 何时使用工具类,何时使用接口的静态方法?
  • 如何减小重复思考,如何界定边界?

参考资料

相关文章
相关标签/搜索