锁定老帖子 主题:一个经典的Spring IOC疑难症状释疑
精华帖 (0) :: 良好帖 (4) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2013-08-08
stamen 写道 to:downpour
接口是为了隔离,这一点是接口给我们带来的好处,但是接口也同时带来了更多的类,这是获取好处的代价。如果说哲学问题的话,就是任何好处都是有代价的。所以前面我们讨论的是什么时候用的问题?而不是接口好不好的问题。 我觉得,你所说团队协作和使用不使用接口没有直接的关系,我写一个类,只要方法签名好了,他就可以去Mock(Mockito Jmock 或者直接子类扩展)。个人觉得说方便团队协作才引入接口是对接口本质的误解。 至于接口的本质是什么,他和类的本质区别在哪里,目前个人的理解是这样的: 接口站在程序或框架最高抽象的角度,描述实体交互关系,忽略实现细节,以便通过接口,将程序或框架的全貌勾勒出来,达到先整体后细节层层推进开发程序的目的,确保在稳定的前提下使实现拥有无限的可能。 这里以Spring框架为例来进行说明吧:Spring通过BeanFactory, ConfigurableBeanFactory等接口勾勒出了Bean创建的“蓝图”,然后通过XmlBeanFactory StaticListableBeanFactory等这些实现类以各种方式实现这“蓝图”,再如Spring定义了ApplicationContext接口,接口中描述了应用上下文的“蓝图”,而使用FileSystemXmlApplicationContext(Spring 1.0就有),AnnotationConfigApplicationContext(Spring 3.0 才有)等这些实现类,实现这个适用于不同场景下的蓝图。 针对上面的例子,我们来看Spring为什么要定义BeanFactory和ApplicationContext接口?我想至少有以下两点原因: 1)从宏观上描述了Spring这个IOC框架的“蓝图”,使框架在此蓝图下保持稳定,保证经典“开闭原则”的“闭”; 2)使Spring框架可以不断在原来精心设计的“蓝图”下,自由挥洒,不断扩展,使Spring有无限的实现可能 (FileSystemXmlApplicationContext,AnnotationConfigApplicationContext即实现了不同的上下文场景),达到证经典“开闭原则”的“开”; 这里没有涉及到任何“团队协作”的问题,而是框架扩展性和稳定性平衡的问题。所以回过头来,如果你的Service不会有多种实现,不会有多种实现场景,那么使用接口是没有任何好处的,只会增加类的数量,这违反了“简单就是最好”的原则。如果你的Service在不同的场景下拥有不同的实现(通过配置注入不同的实现),那么这时你再把它定义为接口才是适合的。 你说了那么多,我仔细看了一下,感觉你的逻辑推导和结论不是一回事,所以不敢苟同。 另外,团队协作是软件工程指导论的范畴,用此来讲具体的项目是合适的,用来讨论框架是不合适的。我个人经历过的最大的项目有超过130个人共同参与,包括美国人、德国人、印度人和中国人。我们四国的架构师在讨论的时候,得到的共同结论就是团队协作和沟通是决定项目成败的关键。至于你不承认引入接口可以更好地进行沟通,只能说明一个问题,那就是你的水平太低,无法理解大型项目的运转。按照你的逻辑,我们四个国家的130多个工程师都对接口本质的理解错了? 我觉得你应该认真检讨一下你的态度,对于哲学选择问题,究竟是随意下结论说别人误解了呢,还是自己再好好思考一下。从头到尾的讨论,我都已经表明了态度:这个问题很难回答,但是我们经历了很多好处之后,倾向于选择使用接口。而你的态度却总是在试图找别人的毛病,而不去思考在这个东西的背后到底蕴含了什么样的问题。 讨论就此结束!虽然我已经不做技术有2,3年了,但我还是深深为中国的程序员感到脸红!我们需要的是海纳百川,学以致用,而不是在没有经历过的时候高谈阔论,异想天开。 |
|
返回顶楼 | |
发表时间:2013-08-08
to downpour
不要动不动就这人水平太低 那人水平太次吧。以理服人才能让人心悦诚服。也不建议动不动拿曾经参加过多大项目和多少人的团队合作过作为理由,EJB是SUN做的,不见得就没有问题,如果只是在回顾光荣的历史,只能说明已经跟不上时代的步伐了。 |
|
返回顶楼 | |
发表时间:2013-08-08
这个题目竟然还能扯开这么长的回复,不容易啊!
|
|
返回顶楼 | |
发表时间:2013-08-08
最后修改:2013-08-09
站的角度不同可能看到的不一样;
假如我站在一个开发人员的角度,发现: 1、我写的项目没有想象的那么大; 2、我写的很多DAO、Service接口都只有一个实现; 3、我写的很多组件都是给自己使用的; 所以此时我上来就定接口,有啥意义吗? 因为有决定的控制权; 此时我和stamen大哥一样的观点; 假如我站在一个所谓的架构师的角度看,恨不得: 1、都给我先定义接口,然后好扩展;因为以后可能会改; 假如我和另一个团队协作,我希望: 1、告诉我怎么拿到API,然后用即可,升级的话,换下jar包就能工作就好了;此时downpour大哥所说的接口隔离很重要; downpour 引用 接口的使用与系统内系统外其实关系不大。接口所表达的契约原本其实并不是用于与第三方进行交互的,而是起到一个编程层次的隔离。
这个我也是这么认为的,但我表达的是:如果自认为可扩展,就比如我之前也认为我的DAO/Service会扩展,上来先写接口,然后实现;但在实际用的时候扩展的几率是非常少的。这个接口是不是有点多余呢? 还有如果Service写个接口,并把接口暴露给团队,这会造成一堆的crud暴露给其他人,人家可能想要的API只有5个,但是我给他至少4+5个。让我看一堆的crud这样合适吗? 因为代码我有控制权,万一哪天真的要切换,我写个adapter也无所谓,但是要切换所有,是不是跟重写没啥区别呢?类的方法签名本质不也是一种隔离吗? 如果是提供给团队的其他人使用,我可能是先定义接口,再实现,这样它查阅也方便,而且到时候可能要导出API,没必要让他知道实现。 |
|
返回顶楼 | |
发表时间:2013-08-08
最后修改:2013-08-08
其实我的观点很明确:
不是说接口不好,只是强调,Service可能并不存在很多实现及扩展的类,不用接口反而可能更简洁更方便。 其实,我在工作中大量使用到接口,我写的很多框架及开源项目,如ROP(https://github.com/itstamen/rop),都是充分使用了接口的。 |
|
返回顶楼 | |
发表时间:2013-08-14
支持楼上两位, 在现实当中的很多项目中,感觉接口有点泛滥了,很多工具类都用了接口,真是头大。系统中有很多可变部分和不太可能改变的部分,在设计时要区分下吧
|
|
返回顶楼 | |
发表时间:2013-08-14
凡事都用接口,或者凡事都不用接口 都说明对接口存在误解,要区分什么时候用 什么时候不用需要下些功夫。
|
|
返回顶楼 | |
发表时间:2013-08-14
stamen 写道 凡事都用接口,或者凡事都不用接口 都说明对接口存在误解,要区分什么时候用 什么时候不用需要下些功夫。 框架级别肯定要用接口,如果不确定是否需要扩展请用接口,确定不用扩展可以不用接口,要不要扩展得看业务规划很难界定,综合看来一般公司还是为了避免一些问题都强调用接口。 |
|
返回顶楼 | |
发表时间:2013-08-15
看了这么多高人的回复,也说下我的个人见解
1. 关于接口 其实stamen和downpour讨论的上下文不在一个层次,毕竟经历的项目差别很大。一个是企业级大项目,子团队之间交互协调频繁所以这个时候接口设计要优于直接实现类。但是stamen更偏向于相对小的项目实现,更多的接口设计没有体现出它的好处反而带来了更多的代码量。好比建造一座大厦,肯定需要非常详细的前期调研,分析,设计然后实施同时还得有非常严格的监理;但是如果建造一套普通的民房,可能同样的步骤会显得有些繁琐,弊大于利。所以站在实用派的角度不关心什么接口本质,我觉得用不用接口看场景,两种大牛体现的是两种截然不同的场景。 我个人在工作中还是比较少用接口设计,也和同事争论过,站在程序员的角度我觉得如果没有以下的需求可以不用接口: a. 需要和其他子团队有API调用 b. 业务稍显复杂,最终实现暂时无法确定。 c. 纯粹个人爱好,几个屌丝程序员一致同意接口设计。 对于长期项目考虑,我觉得等真正项目壮大再去进行接口重构也不是不可以,至少前期项目节约了时间和代码量。所以这不能作为必须使用接口的一个借口。 2. 关于讨论 两位实际上是站在不同的角度去争论,一个是偏管理一个是偏开发。管理需要控制团队协作,项目开发进度,沟通成本等标准,但是程序员可能更考虑自己的workload以及编程习惯。所以我觉得求同存异是最好的,起码大家都觉得在特定的场景下用接口最好。当然了,如果在项目中我觉得作为管理者或者架构师可以通过权力去决定要不要用接口。 :) 另外,我看到很多争论最后都不欢而散是国内程序员不太好的特征。争论我个人很推崇,但是不能搞人身攻击和以身份压人。所以请老板去澡堂子洗澡是最好的争论场所,毕竟在工作中本身权力和地位就不对等(不觉得有多么好的PM,完全不用权力压人)。 兼容并包,海纳百川! |
|
返回顶楼 | |
发表时间:2013-08-15
java从5开始加入了Proxy功能但是只能对接口有效 而spring 当类默认有接口就使用java原生的Proxy做拦截 而没有接口就使用cglib,asm在内存里动态生成一个继承原有类的子类。 然后再子类里覆盖并调用父类方法完成拦截功能。所以如果用cglib的方法会启动比较慢 而且会大量使用 java的永久保留区。所以我觉得方法2 是spring aop的推荐使用方法。 |
|
返回顶楼 | |