2005-09-13 关于IoC、低耦合、配置文件及其本质意义的思考

看了一篇关于IoC的Blog《你真的了解Ioc与AOP吗?》,很是有点感想。

我之前对IoC了解一些但实际大规模应用的机会比较少,感觉它可以通过两种方式来改善耦合度关系:

1,通过"注入"实现功能替换。简单的"注入",可以通过seter或者Constructor来实现。之后可以在运行期的装配阶段把各个注入类和宿主类组合起来。简单"注入"的缺点是,还是要将具体的注入类写死在装配方法中。

2,为了解决简单注入的问题,有人利用反射+配置文件实现了注入,现在只要修改配置文件就可以实现注入类的替换了。

所谓的"注入",可以理解为一个回调的过程:把宿主类中要在运行期决议/替换的功能单独作为一个类来实现,然后把这个类的抽象(抽象类或者接口)作为宿主类的一个接口(通过seter或者constructor来赋值),最后在运行期把一个实现具体功能的实例赋给宿主类。上述的实现,宿主类要显式的标明注入类的接口类型,并且在装配阶段要显式的new出注入类,然后赋给宿主类的对应接口。这种事情,好处自然是有的了,就好像AbstractFactory或者Builder模式:只公开接口,把具体的实现抽离出来,这样可以方便的实现具体实现的替换。可是仔细看一下,这样的实现,耦合度从代码中转移到了装配类中。

而配置文件的方式,把类的装配工作以配置文件的形式实现了,这样不用修改代码、编译就可以实现注入类的替换。这样做的好处更是有的,不管怎么说,能够不修改代码实现功能的替换至少在发布方面是能够带来不错的效果。至于在代码方面能够带来多大程度上的好处,我想可能还是要视环境和应用的场合来定吧。毕竟这样做的复杂程度要比简单实现高很多了。而且这样的实现,事实上是把耦合从装配方法中转移到了配置文件中。

其实在IoC实现中花了很多的力气来做类型的匹配工作......宿主类和注入类的接口对应,这个是强类型语言所不能避免的。既然如此的话,那么无类型的动态语言实现IoC应该是非常的容易并且效果应该是不错的--可是同时负面效果就是运行期才能进行类型的识别和匹配工作容易出错,但目前似乎配置文件的方式也无法避免这个问题。

进一步的,配置文件其实也是可以演变、进化的。首先就是配置文件中的内容是否可以以元数据的形式出现?又或者以一个程序集的形式出现?该程序集其实就是配置文件或者元数据功能上的替代者--虽然修改不方便了,但是同时带来了安全上的保证。可是这样一来,我们又要面对编译的问题。呵呵,两难吧。

当下形形色色的配置文件已经泛滥成灾了,怪不得RoR要火爆起来。其实就配置文件来说,本质上是为了把耦合的位置从不可修改的编译代码中转移到一个可修改的文本文件中,这样就可以在替换部分功能的时候免除掉"编译"这个环节,为的就是这个效果吧(不知道这样说是否正确)。 虽然可以不用修改代码了但还是要修改配置文件,我个人感觉这本人本质上其实还是一回事。话说回来,如果这个趋势发展到极致,我想可能大家可以只用配置文件来写程序了,宿主程序则退化为一个配置文件的解释器--事实上,这个也是可以实现的,Eclipse和SharpDevelop的宿主程序已经是这样的一种东西了。XML的配置文件加一个解释器不就是一个新的语言么?如果不用XML做配置文件,而是用类似脚本的方式来定义配置,那么这个配置文件其实就是一个解释型的语言了。然后,为了提高这种配置方式程序的效率...... 我们兜了一个很大的圈子之后又转回到编译语言上来了。从这个角度上来说,这是一个平衡度的问题。 从更高一点的角度来看,这是一个螺旋式进化、演变、上升的过程。从现实的角度来看,未来二十年应该是解释语言和动态语言的天下。

退后一步来看这一切,我们当初为什么要OO,是为了降低大型软件中面向过程的封装问题导致的复杂性。有了OO之后,发现一切并不是那么的美好,为了降低对象之间的耦合度、增加灵活性,于是有了设计模式。人们应用了设计模式,发现调试不方便了,复杂性又提高了。IoC可以理解为是模式的一种吧,但是换一个角度来看,它不就是一个回调函数的OO方式的实现吗?我们果然是又转回了起点,下一步又要转向哪里呢?

这其实,都是为了解决软件的一种复杂性而导致的另外一种复杂性,所不同的就是人们可以选择自己更能够接收哪种复杂性。

最后更新于