今天和大家聊下java中的面向接口编程。
提到java中的面向接口编程,很多人会自然而然的联想到抽象类,因为在面试的时候,很多的面试官也会问到关于接口和抽象类的区别。但是我做面试官的时候,我从来不会这样去问,因为你一旦这样问了,好多的应聘者就开始背上八股文了,什么接口用interface修饰,抽象类用abstract修饰等等。。。 这些毫无意义的八股文,并不是我想听的答案,所以我通常会问:在你的实际工作中,有哪些实际的场景使用到了接口(抽象类)?是基于什么样的考虑而使用的接口(抽象类)? 这种问题才能真正的考察出一个人的设计思路和代码经验,才能把那些八股文背的很溜,但是工作能力很差的人排除在外。
那么我说下我理解的接口和抽象类的区别。我觉得,很多网上和教程说的这两者之间的区别,说的都很抽象,不容易理解。其实这两者之间的区别,本质上很明显,一句话就可以解释的很清楚:接口就是定义了一种规范而已,而抽象类就是为了做代码复用的。他们的区别就是这么简单,你了解了他们之间的这种区别,那你自然而然的也就知道了,该什么用的场景使用接口(抽象类)了。我不理解为什么好多人,都喜欢把一件很简单的事情,搞的特别复杂。
不知道大家在做java开发时,有没有为每个service类都写一个接口的习惯。记得去年的时候,我就发表过一篇文章,说这种行为纯粹的是在滥用接口,除了增加了开发工作量,没有任何的意义。然后就遭到了评论区很多很多人的狂喷。当然了,这也是一件好事,如果没有这些人喷我,我还真的不知道,原来我已经变得如此优秀。
那我为什么说这种行为是在滥用接口呢?回答这个问题之前,我们首先思考一下,面向接口编程的意义是什么?
第一个意义,就是做了调用方与实现类的解耦,解耦了以后,如果后面想替换一个实现类,就可以任意的替换,没有任何的影响。比如说slf4j,你使用了slf4j以后,如果你想使用log4j,你就直接引入log4j对应的jar包,如果后面不想用log4j了,想用logback了,你就直接把log4j的jar包替换成logback的jar包即可,对代码没有任何的影响。但是你试想一下,如果没有面向接口编程的思想,没有slf4j,你想把log4j替换成logback,这种改动量会有多大?
第二个意义,就是代码的可维护性与可扩展性。还是拿之前我曾经说过的审批流系统为例,这个审批流系统里,会有很多很多的单据类型,比如说:报销单据、请假单据、采购单据等等,而且业务也经常会新增、删除单据类型,或者对某种单据类型做业务变更,那这时我们就要考虑,我们的代码要如何的应对这种频繁的业务变化,使我们即可以快速的开发,又可以不影响存量的流程呢?
我们思考,不同的单据类型的主要区别是什么,我们可不可以把这些区别,给它抽象出来一个接口,然后让每个不同的单据,实现它的接口呢?这样业务每新增一个或者删除一个单据类型,我就只对应的新增或者删除一个实现类即可。即使说对某个单据类型做业务变更,也只是修改这个实现类,也不会影响到其他的单据。基于这样的想法,我简单总结出了每个单据的不同之处,然后封装成了接口,代码如图所示。
其实我理解的面向接口编程的意义,主要就是上面这两点。但是,无论哪一点,我们都可以看到,只有一个接口下有多个实现类的情况,面向接口编程才有意义。
那在回到我上面提到的问题,为每个service类都写一个接口的这种操作,大家有谁见到过,一个service接口会有多个实现类的情况呢?那service接口的意义又在哪?所以我说这种情况,完全就是在滥用接口。
大家怎么看呢?欢迎评论区留言讨论