写点什么

通过阅读 SpringCloud 源码 来 理解接口和抽象的区别

作者:悟空聊架构
  • 2021 年 12 月 07 日
  • 本文字数:1680 字

    阅读完需:约 6 分钟

大家好,我是悟空呀。


我们通过阅读 Spring Cloud 源码来理解下 Java 中的接口和抽象的区别。


我们最熟悉的应该是这个:接口中定义的方法,不能自己实现,必须由实现类来实现,抽象类中可以包含已实现的方法。

关于接口的一些特性

首先我们看下接口有哪些特性。我们用接口的话,无非就是用 interface 来定义。比如我们在使用 OpenFeign 组件时,都会这样定义一个 FeignClient,用来远程调用的。


public interface ProductFeignClient 
复制代码


然后接口中,我们是见不到属性的,只能声明方法。比如在 OpenFeign 源码中,我们可以看到接口是这样定义的,只有一个方法。而且方法是没有方法体的。


interface Targeter {
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target);
}
复制代码


然后当类实现接口的时候,必须实现接口中的所有方法。在 IDEA 工具中,如果没有实现接口中定义的所有方法,将会提示错误。我们可以直接用 IDEA 的提示,来一键生成接口的所有实现方法,非常方便。

关于抽象的一些特性

抽象类无非就是用 abstract 修饰起来。比如在 OpenFeign 源码中就有用到抽象类。


public abstract class Feign { }
复制代码


然后这个抽象类里面定义了一个抽象方法:


public abstract <T> T newInstance(Target<T> target);
复制代码


然后有一个类继承这个抽象类:


public abstract class AsyncFeign<C> extends Feign {}
复制代码


然后这个类通过 @Override 注解重写了抽象接口:


@Overridepublic <T> T newInstance(Target<T> target) {  return newInstance(target, defaultContextSupplier.get());}
复制代码


另外抽象类 Feign 是可以有自己的方法实现的,比如这个方法 configKey


public static String configKey(Class targetType, Method method) {// 省略其他代码}
复制代码


然后抽象类 AsyncFeign 里面还可以自定义属性:


private final Logger logger;
复制代码


根据上面的例子,我们总结下:


首先抽象类是不允许被实例化,也就是不能 new Feign()。


然后抽象类是可以包含属性的,方法也可以有实现的,也有需要子类来实现的抽象方法,比如上面的 newInstance 方法。当子类继承抽象类时,必须实现抽象类中的所有抽象方法。


一开始接触抽象类时,会感觉很奇怪,为什么需要抽象类呢?这不是把问题弄复杂了吗?抽象类还多了一个层级呢。

抽象类带来的好处

首先,抽象类带来的很大的作用就是实现代码复用,比如当有多个子类有相同的属性或方法时,我们可以抽象出一个公共的类,然后子类继承这个抽象类,当然,这个公共类可以是普通父类,也可以是抽象类。


但是抽象类中的方法可以交给子类去实现,让子类有不同的功能。


另外呢,因为抽象方法必须由子类来实现,所以可以规范开发,防止开发人员忘记实现抽象方法。

接口带来的好处

首先我们总是听到:多用组合,少用继承。这个组合代表的意思就是用多个接口来实现不同类的功能。


比如鸵鸟和麻雀都属于鸟类,如果我们抽象出了一个 Bird 类,然后鸵鸟和麻雀都继承 Bird 类。然后 Bird 类有一个抽象方法:fly(),但是鸵鸟是不会飞的,它实现这个方法根本没有意义。


但是有同学就会说了,何不抽象出两个类:会飞的 Bird 类和不会飞 Bird 类。然后鸵鸟继承不会飞的鸟类,不就可了吗?


但是你想想,如果再增加一种情况,会不会抓鱼,那排列组合是不是就有四种抽象类了?如:


  • 会飞会抓鱼抽象类。

  • 会飞不会抓鱼抽象类。

  • 不会飞会抓鱼抽象类。

  • 不会飞不会抓鱼抽象类。


但是如果我们用接口就方便多了,我们定义了会飞接口,会抓鱼两个接口,不同的鸟类继承相关接口就可以了。


另外就是在远程调用框架中用得非常多,调用者只需要关注抽象的接口,不需要了解具体的实现,具体的实现代码对调用者透明。接口实现了约定和实现相分离,降低了代码间的耦合性,提高代码的可扩展性。


好了,接口和抽象的内容就总结到这里了,不知道各位在工作中用抽象多还是接口多呢?


作者简介:悟空,8 年一线互联网开发和架构经验,用故事讲解分布式、架构设计、Java 核心技术。《JVM 性能优化实战》专栏作者,开源了《Spring Cloud 实战 PassJava》项目,公众号:悟空聊架构。本文已收录至 www.passjava.cn

发布于: 2 小时前阅读数: 5
用户头像

用故事、大白话讲解Java、分布式、架构设计 2018.05.06 加入

公众号:「悟空聊架构」 【个人博客】www.passjava.cn 【开源项目】基于 SpringCloud 的一套面试刷题系统 【Github】https://github.com/Jackson0714/PassJava-Platform

评论

发布
暂无评论
通过阅读 SpringCloud 源码 来 理解接口和抽象的区别