首页 > 编程知识 正文

java什么时候用接口,什么时候用抽象类,Java抽象类和接口的区别

时间:2023-05-03 22:31:36 阅读:276095 作者:2714

很多人在面试过程中都会被问到这个问题,语法上的区别大家都知道,但是如果面试时你只说语法上的区别,显然不合面试官的胃口


本文重点关注这两者在设计方面的区别:
接口大家比较熟悉一点,因为现在的MVC架构业务层规范就是先写接口再写实现类,那大家有没有想过,用抽象类代替这些接口,是否可行呢?从语法上当然是可行的,但是不会这样做,为什么呢?大材小用..
举个例子,领导说了,需要有个订单报表,可以导出excel,于是你定义了一个接口和一个实现类:

此时接口就可以完全胜任,无需动用抽象类。程序正常运行,报表导出OK,一切都很完美

后来,领导又说了,商品报表也需要导出,你的第一反应是下面这样嘛?o(╥﹏╥)o

或者是这样?

后面领导又说了,还得加N个报表,并且每种报表都要支持日报、月报、季报、年报....,都用这种方式,能实现嘛?当然可以,但是很明显,一点也不优雅,因为有重复!重复是我们代码最容易出现,也最容易被忽视的坏味道!我们从上面几张图可以很明显看出重复部分,即:

不同点就在于数据统计,其他部分逻辑重复,是可以抽出来的。注意了:抽象类的场景出来了,那就是多态+复用!!我们的类要做一件事情,这件事情分为几个步骤,有些步骤是固定的(复用),有些步骤需要根据不同情况有不同实现(多态),这时候接口就满足不了要求了,因为接口只能满足多态,那我们就应该想到抽象类,我们先看代码,再对其进行介绍:

可以看到,报表导出方法分为四步,被抽成四个方法,有三个公共方法,一个抽象方法为查询报表数据,由于不同的报表,数据查询逻辑不一样,所以它应该被作为抽象方法,由子类去实现。子类只需要实现该抽象方法即可,比如订单子类就去查询并统计订单库,商品子类就去查询并统计商品库:

如此,不管加什么报表,只需要实现这个数据查询方法即可,显然比仅仅实现接口方式要优雅很多。

我们可以看到抽象类就相当于一个模板,模板中有子类可以公用的部分,也有需要子类自行实现的部分,是为模板式设计,它同时具有多态性+复用性;
而接口是对行为的抽象,它只定义一组行为规范,每个实现类都要实现所有规范,叫辐射式设计,它只有多态性;

其实,在实际开发过程中,接口和抽象类并不一定是上面例子中非此即彼的情况,在遇到和上述例子中类似情况时,一般来说,会有这样一个演进的过程(面试时,你可以直接把这个过程讲给面试官,比背他们的区别要来的简单有效):

 1.首先是设计接口IService,定义行为service();

 2.然后是接口实现,你会发现多个实现类中干了一些重复的事情,这时我们再设计一个抽象类AbstractService

 3.AbstractService中定义同样的service()方法,将上一步发现的重复内容提取到该方法中

 4.对于第2步的多个实现类来说,现在重复的部分已经被提取了,剩下的就只有各自特殊的部分了,我们再在抽象类中为特殊的部分定义一个抽象的方法doService()

 5.将第2步的多个实现类去掉implements接口,改为继承抽象类,实现doService()方法,去掉重复部分的内容,只留下各自特殊的部分

 6.接下来,我们要考虑接口还有没有存在的必要了,如果你觉得现在或未来可能有另一种实现类,它并没有和其他实现类重复的部分,那就留下来,让抽象类实现这个接口,那继承体系就是这样:

如果,你觉得不会存在这种情况,那就去掉这个接口,继承体系就是这样:

当然了,是否去掉接口是见仁见智的事情,仅仅根据我上面说的标准来决定可能会有点武断。还用上面两类继承体系举例,下面的继承体系下,如果顶层的AbstractService中方法比较多,充斥着实现细节,看起来可能会比较费劲。相对来说,上面的继承体系下,顶层的IService只有简单的方法声明,可以很明确的表明其设计意图,get到这个意图后,再去看细节部分,就更明了

     

PS:如果有不足之处,欢迎指出;如果解决了你的疑惑,就点个赞吧o(* ̄︶ ̄*)o

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。