IOC模式的思考和疑问

IOC,是现在很火的设计模式,就像当年的Factory和Singleton模式一样。IOC模式为我们提供了真正(?)的松散耦合,但是松散耦合真的这么酷吗?紧耦合真的一无是处吗?不见得。
首先,使用IOC模式就必然会依赖于一些IOC容器,除非你直接使用反射(-_-),比如Spring,这对于勾结的独立性是不利的,试想,如果每次使用java.lang.String的时候都必须import org.springframework…。对于一些要求响应速度的系统而言,IOC的使用必然会降低系统性能(new 的速度肯定比Class.forName块),缓存?忘记它吧,我已经强调响应速度了。再说,IOC跟缓存和池没有必然联系呀。
其次,IOC模式的大量使用会降低一些复杂模块的可读性,要知道,如果你不能写出很好的文档(多数人都是如此),那么代码就是你唯一可以与其他人沟通的语言。如果阅读代码的人不懂IOC,不会使用Spring呢,他如何理解你那些接口的实现?
第三,IOC容器的大量使用会造成额外的维护成本,很显然,你现在不仅仅需要维护你的代码,还需要维护你的applectionContext.xml,如果是WEB应用,则需要注意维护哪些Context-Param。尤其是,虽然代码中不存在耦合关系,但是耦合关系都在配置文件中,你在写出松散耦合的代码的同时也必须去写紧耦合的配置文件,对于一个大型系统而言,大量的配置文件的管理本身就必须付出高昂的代价。
最后,我认为真正意义上的松耦合是不存在的――是的,你可以“依赖”接口编程――但是毕竟还是“依赖”了。既然没有绝对的松散耦合,那么我们是否可以考虑在一定范围内使用紧耦合呢?ArrayList和Collection是紧耦合,你是否觉得不便呢,ArrayList和Iterator更是紧耦合,难道Iterator不好用吗?
考虑一下传统的工厂模式吧,它在一定程度上体现了IOC的思想,但是又没有完全的实现IOC。你可以使用工厂模式实现接口编程,但是依赖关系仍然需要在代码中体现。Hibernate是公认的优秀产品,它没有使用IOC,大量的Factory充斥其中,但是Hiberante的质量和升级速度有目共睹。也许你会说,IOC容器提供了很多底层的东西,例如缓存和对象生命周期管理等,以Spring为例,缓存倒是有,可是生命周期管理就不见得,事务管理还是需要客户介入。再说了,这些都是容器提供的,IOC模式并没有要求。之所以谈这些,主要是考虑实现一个带有缓存和“挂钩点”的工厂,这个工厂提供对象的创建和pool&cache管理但是不提供依赖关系管理。
那么IOC这个模式在哪里使用呢,我认为,应该在构件这个级别使用。构件应该是一个封装的很好的模块,它提供独立的、具有实际意义的功能。通过对构件的粒度的设计控制IOC使用的密度。而构件的内部,可以使用传统的工厂模式,也可以什么模式都不用^_^。只要提供清晰准确的接口,并且封装接口在构件内部的实现,那么即使使用public变量都没有关系!

>那么IOC这个模式在哪里使用呢,我认为,应该在构件这个级别使用。构件应
>该是一个封装的很好的模块,它提供独立的、具有实际意义的功能。通过对构>件的粒度的设计控制IOC使用的密度。

我也深有感触,同意,同意。

如果粒度细了当然也可以,不过这时候我们就应该有图形化的配置工具来管理这些xml文件,能让他和类一起自动产生,就好了。
目前,这种工具的工具做的还不好,以后会发展起来。这应该是趋势。
谁把这个做好了,谁就能雄起吧~~

cats_tiger提出的疑问只是从Spring这个产品来看,Ioc模式和Ioc容器是有区别的。

>写出松散耦合的代码的同时也必须去写紧耦合的配置文件
这是Spring的缺憾,你看看Jdon框架的配置是否属于紧耦合,这里面autowiring很重要,HiveMind的配置也非紧耦合。

我一再强调Pico/Jdon HiveMind的IOC模式实现要比Spring好多,可以多看看这些,有时不是商业炒作得厉害就是好东西。

理解Ioc模式要从一个高度来看,不能局限于某个产品。

另外,cats_tiger的观点"IOC这个模式在哪里使用呢,我认为,应该在构件这个级别使用"是正确的。

不过,我一直认为构件就是组件,Ioc容器本来就是进行组件(构件)管理的容器,这方面是专长。将component翻译成构件,我认为组件更准确。我们不能因为别人提出一些新名词,而以为是一个新概念。

组件和构件俺从来就没有区分过他们,好像是滑鼠和鼠标之间的区别。Jdon框架俺也看过,虽然看的不深入但是感觉确实不错,但是从配置文件的角度考虑,也是比较麻烦的,Banq是作者当然觉得简单。另外,无论是Spring还是Jdon或者Pico,IOC的使用都是灵活的,可以在构件(原谅我仍然使用这个词)内部也可以在构件之外。我的观点是构件内部使用GOF的设计模式,并通过接口向外界提供服务。构件和构件之间可以使用IOC模式以体现松散耦合的特性。
另外,单从IOC容器的角度考虑,我是真喜欢轻巧的PicoContainer,可是Spring提供的各种小工具和模板确实好用,我更喜欢。

前两天还见到有人提出现在不是代码编程的时代,而是配置编程的时代。同感啊。

>构件内部使用GOF的设计模式,并通过接口向外界提供服务。构件和构件之间可以使用IOC模式以体现松散耦合的特性。

是这样,这实际是一个Ioc模式使用的粒度问题,粒度越细,凡是每个类都使用Ioc模式,都使用Ioc容器配置文件来配置,就麻烦了,最后是一个一个功能服务为主或为模块使用Ioc,就是你说的构件之间使用Ioc模式。

不过:Ioc模式和GOF模式中的工厂模式还是可以结合在一起使用,这样用Ioc模式来提升工厂模式的灵活都和可配置性,这种结合就象以前class.forName和工厂模式结合使用一样。

还有一点:使用Ioc模式进行编程,实际是走上一个全新的编程模式,如果说传统编程习惯的人还可以凑合使用Java编程,那么当他遇到Ioc模式编程时,会非常不习惯,会产生一种割裂感。

但是 Ioc已经深入到JSF/Tapestry表现层 组件层甚至持久层时,一种全新的时期到来了,这如同翻上一座高山,看到新的一片美景,以后的技术发展会完全基于Ioc向前发展,有些人预期Java会灭亡,不错,Java语言已经在我们Ioc这座山的脚下了。

以前我说是否会GoF设计模式是衡量一个程序员是否OO的标准之一,那么现在是否Ioc,是衡量一个程序员是否进入现代编程的标准之一。

>使用Ioc模式进行编程,实际是走上一个全新的编程模式。
Banq对新技术的敏感程度令人佩服。但是我并没有感觉到IOC如此重要性和和“全新”特性。很早以前就有“依赖倒转原则”和“面向抽象编程”了,这应该是IOC的前身吧?
IOC就是通往“松散耦合”这个终极目标的一个途径而已。而松散耦合也是有限度的,就好像不能每个类都IOC,也不能离开IOC容器就统统使用Class.forName。之需要保证“构件内部的变化不会被外部感知”即可,这就是松耦合。至于构件内部,我甚至提倡使用public字段替代set/get,多方便呀,只要限制构件外部不能使用即可。这种情况下,IOC根本无从谈起。

>1使用IOC模式就必然会依赖于一些IOC容器
实际上,良好的设计可以将这些依赖转移到一个配置文件中。对于web应用而言,这根本不是问题,只要你用流行的mvc框架,你的代码压根就不需要出现import org.springframework……。其他的情况,对于api的引用只需要在系统启动的时候import一下就可以了。

>对于一些要求响应速度的系统而言,IOC的使用必然会降低系统性能
这个说法没有意义。

>其次,IOC模式的大量使用会降低一些复杂模块的可读性,要知道,如果你不能写出很好的文档(多数人都是如此),
大部分的情况只要你的接口上有注释说明一下就可以明白了。如果这都做不到,干嘛要用OO的java来做?

>第三,IOC容器的大量使用会造成额外的维护成本,
这也应该是楼主自己想的,俺们从来没遇到过这种情况

>那么IOC这个模式在哪里使用呢,我认为,应该在构件这个级别使用。构件应该是一个封装的很好的模块,它提供独立的、具有实际意义的功能。通过对构件的粒度的设计控制IOC使用的密度。而构件的内部,可以使用传统的工厂模式,也可以什么模式都不用^_^。只要提供清晰准确的接口,并且封装接口在构件内部的实现,那么即使使用public变量都没有关系!
偶觉得这一点说的倒是也没错。不过用了ioc也不什么时间啊~为啥不用呢

> 还有一点:使用Ioc模式进行编程,实际是走上一个全新的编?> 模式,如果说传统编程习惯的人还可以凑合使用Java编程,那
> 吹彼龅Ioc模式编程时,会非常不习惯,会产生一种割裂感
> ?>
> 但是 Ioc已经深入到JSF/Tapestry表现层
> 组件层甚至持久层时,一种全新的时期到来了,这如同翻上一
> 呱剑吹叫碌囊黄谰埃院蟮募际醴⒄够嵬耆Ioc向
> 胺⒄梗行┤嗽てJava会灭亡,不错,Java语言已经在我们I
> c这座山的脚下了。
>
> 以前我说是否会GoF设计模式是衡量一个程序员欠OO的标准?> 一,那么现在是否Ioc,是衡量一个程序员是否进入现代编程?> 标准之一。

哈哈,偶一前跟一个c++程序员吹嘘ioc时,被笑了一通,人家这不是编程的基本原则吗?有啥好说的。
现在轮到banq被笑话了

人家这不是编程的基本原则吗
sorry,这里掉了一个说字

我觉得用IoC对设计一个具有很大的变数的系统很有用处,缺点是增加了系统的复杂性。

Acegi Security是一个典型的IoC程序,花了一个星期才弄清楚里面的运作原理,了解了里面各个部分插入之间的关系,而我要求的功能如果全部自己用传统的方法编程实现的话可能速度只要一两天,这是由于Acegi IoC粒度太细,极大的增加了系统的复杂程度和熟悉成本。

但另外一方面发现以前认为很复杂的几个需求用Acegi只需要插入几个简单实现的class即可实现,对于security这样的需求,每个系统根据业务的不同可能有不少的差别,用 IoC来实现的话才能满足通用的需求。所以对于code library,IoC是个重要的指标,缺少IoC就会失去很大的灵活性而失去很多用户。

我觉得IoC(这里主要是指Spring)的一个很大的缺点是application context configuration 缺少规范和指引。特别是那种非string的property, 如string to class 是通过一段什么asText程序来转换的,这里就会存在太多个人喜好和习惯,另外一个人可能要读完原来的程序才知道这个配置是什么意思。系统出了问题之后,需要叫来几个开发这个系统的所谓的“高手”在application ctx 里面飞快的打进几行字,系统才又开始工作。对比起来以前的那种jsp, php多简单,everyone knows how to fix a problem!

我同意楼上的说法,就是IoC将会给OO带来一些变革,现在的new instance的方法会不会淘汰呢,都是很有意思的猜想。

这玩意好象在csdn见过呢?
俺不愿意吹毛求疵,知道楼主怀疑的是IoC容器。
但是,题目是对IoC的疑问,那还是吹一下……没有容器就不能IoC了么?
楼主可能更多说的还是依赖注入吧。依照martin flower的定义。而IoC,很久以前,从终端机转向C/S时代就已经是一种控制反转。而面向接口编程更多的也是为了更加容易控制反转。其实没有用Spring Pico等的时候,大家无形中已经在控制反转的方式编程解耦了。

为了说明我的观点"使用Ioc模式进行编程,实际是走上一个全新的编程模式。",本站正好有一个帖子:

http://www.jdon.com/jive/thread.jsp?forum=91&thread=24127

这个帖子楼主觉得为便于JMock测试,更改代码结构后很不习惯,其实他不知道这正是基于Ioc模式的一个新的编程方式,对以前编程方式有所改变,不但面向接口,一个类对其他类的调用只要提供setXXX或构造参数即可,测试或运行的装配由相应的框架完成。

另外,纠正blueoxygen 的一句话:这玩意好象在csdn见过呢?

Ioc模式早期讨论是2004年在Jdon开始的,当然程序员杂志等媒体有些翻译文章,但是真正理解后讨论研究是在Jdon,看下面几篇文章:

Ioc模式

Pico、JMX、微容器以及对象的易管理性

看看这些文章的后面讨论,可见当时大家还是初次接触,甚至有人说我在“胡言乱语”。

当然,其他网站也可能在这个时期有讨论,这里不做引述。