zoukankan      html  css  js  c++  java
  • JDK8漫谈——增强接口

    解决什么问题

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

    背后思想

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

    内容介绍

    组成部分

    接口一直不断在增强,但是总体来说,还是只放抽象的内容,不放实例化相关的内容。

    • 公有常量。
    • 公有方法。没有具体实现,一般不需要写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

    实战

    最佳实践

    减少类爆炸

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

    @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));
    }
    
    • 减少需要思考多份职责,需要关注接口还需要关注类。
    • 减少类,提供代码优雅度。

    内置处理

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

    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方法

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

    再次思考

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

    参考资料

  • 相关阅读:
    HTML5结构
    HTML5新增的非主体元素header元素、footer元素、hgroup元素、adress元素
    CF GYM 100703G Game of numbers
    CF GYM 100703I Endeavor for perfection
    CF GYM 100703K Word order
    CF GYM 100703L Many questions
    CF GYM 100703M It's complicate
    HDU 5313 Bipartite Graph
    CF 560e Gerald and Giant Chess
    POJ 2479 Maximum sum
  • 原文地址:https://www.cnblogs.com/ansn001/p/9375792.html
Copyright © 2011-2022 走看看