面向接口编程的思考
????? 随着IOC各种实现(比如Spring/guice)出现,特别是Spring的影响力的扩大化,面向接口编程范式被提出来,于是企业编程中便大量地使用IOC技术,典型的展现形式是一个接口对应一个(几乎全部是仅有一个)实现,接口和具体的实现类的绑定通过IOC容器实现。相信这种现象很多人都看到过,并且现在依然在这么做,甚至没有停下来思考过合理性。我记得刚刚进入公司的时候,看到应用中有大量的spring配置文件,各种DAO和各种Manager都配置在其中,而且几乎每个接口基本都是只有一个实现类。我尝试怀疑过这样做的合理性,但是被“资深人士”解说,“这是面向接口编程范式,只依赖接口,可以隐藏实现细节,隔离实现类使用的依赖,适应新的变化。”类似的话,然后我崇拜地点了点头,表示恍然大悟,其实我并没理解。
???? 现在回过头来看看,这些话是不是真的名副其实呢?“只依赖接口,可以隐藏实现细节”这句话,我表示赞同,但是这不是使用接口的有力证据。事实上,类(class)本身也是对功能的抽象,也隐藏了实现细节。“隔离实现类使用的依赖”这句,我表示不完全苟同。举例说明,假如A是接口,AImpl是A接口的实现类,B是A的客户端,如果B直接依赖AImpl的话,会把AImpl依赖间接依赖进来,但是是编译时依赖。如果B依赖A接口,那么最终在运行时AImpl最终会被注入到B中,顺带着AImpl的依赖会带进来,不过这个是运行时依赖。通过这个,不难看出,只是把依赖搞成了编译时和运行时,当然运行时的依赖有时候会好点,比如通过OSGi可以暴露出很少的类,从而减少依赖冲突。再来看“适应新的变化”这句,前边也说到,几乎每个接口都只有一个实现类,那么貌似适应新的变化并不具备说服力。当然,我并不是完全否定面向接口技术,也不是对IOC嗤之以鼻。我只是想表达一下“一个接口一个实现”的问题。
????? 接下来,什么时候情况下才考虑使用面向接口技术呢?要搞清楚这个,首先谈下接口的意义。个人理解如下:接口是对功能的抽象,更是对功能变化的抽象;接口是模块间的一种契约。接口这两点特性决定了接口的使用方式,对于独立的模块(甚至是独立的系统)之间的交互,使用接口是推荐的方式,甚至是必须的,这样隔离了模块实现细节,对模块之间的独立开发重构以及测试都起到了关键作用。对于模块内部那些经常变化(至少目前业务可见范围内)的功能单元,可以抽象成接口,这样方便以后提供新的实现类来增加新的功能,这个不是必须的,但是是推荐的。对于模块内部几乎不会发生变化的功能,就没有必要提供抽象成接口了,因为很少变化,而且是在模块内部使用,所以以Class的形式抽象就完全可以了。
?
?如上图,蓝色区域代表一个模块甚至是一个系统,黑色条带表示接口,黄色表示具体的功能类,绿色区域表示实现了接口的功能类,箭头表示依赖或者实现接口。这幅图基本描述了,接口的使用方式,模块之间使用接口依赖,模块内部多变功能使用接口抽象,模块内部很少变化的功能不使用接口。
????? 好吧,就这么多吧。第一次写技术博客,个人的理解和高度有限,难免会有误差,欢迎拍砖。
?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????