面向对象的设计的重用性一直是他的一个重要特性,为了有效定义这一特性,又引申出面向对象设计的几个原则:高内聚、低耦合、功能单一、优先使用聚合、面向接口编程等。依赖这些原则和前人的经验,又发展出形形色色的模式,分析这些原则和模式可以发现,或许是因为硬件的快速升级,我们走的是一条牺牲软件效率以提高其重用性的道路。而沿着这条路走出的另一步就是现在出现在.NET中而Java已经有了相当发展的IOC框架(以上纯属个人观点)。目前.NET中的IOC框架较受关注的有Spring.net和Castle等。
IOC的中文直译是控制反转,这个概念有些大而空泛,于是有人提出了依赖注入(DI),并将其做成一种模式,所以也可以说,IOC框架是快速实现依赖注入模式的一种工具。依赖注入,顾名思义,类间的或者接口间的依赖关系并不是在编译时就明确建立的,而是通过某种手段,在运行时建立的,或者可以称为晚绑定、动态绑定。依赖注入又可分为3种方式:接口注入、设值注入、构造器注入。接口注入很多人在不经意的时候可能都使用过,就是在配置文件中确定对接口的调用实际上是用的是哪个具体类;设置注入针对的是类的属性,将这些属性的值在配置文件中注入;构造器注入针对的是包含参数的构造函数,将这些参数的值在配置文件中注入。很简单的原理,扩展开来,就成为下边要说到的框架。
Spring.net移植于java的spring框架,目前版本为预览版3,它基本可以算作spring框架的.NET实现版本。Spring.net是一种低侵入式的框架,它是由一系列松散的平行框架组成。Spring.Core core就是一个对象工厂(ObjectFactory), 它通过配置中的对象定义来创建对象,它的目的是消除对象的new操作。在配置文件中,除了定义对象的一些属性外,还能定义对象之间的相互关系,这就使得对象之间的耦合延迟到了运行时,如果针对接口或抽象类进行编程,则还可以通过具体对象的不同实现来定制系统的行为。 Spring.AOP 这是按AOP联盟的接口定义来实现的,AOP即面向截面编程,其核心是通过给对象创建一个动态代理对象来接管对象的操作,这样就能对操作进行前置和后置处理了。Spring.Data 这是一个由第三方实现的整合到Spring内的数据访问组件,目前已包括了NHibernate的实现部分。Spring.NET还显得不够成熟,一些功能因为平台的局限性而导致了移植上的困难。其核心为IOC框架和AOP实现框架,所有这些可以组合起来共同工作,也可以根据需要选择其中一部分单独工作。相对于其他框架而言,Spring.net是从java移植而来,很多思想也是直接转嫁过来的,例如以配置文件为核心、MVC框架等,以配置文件为核心是一个争论的话题,各说各有理,支持的人认为这提供了强大的灵活性和透明性,反对的人认为这大大增加了配置文件的复杂性和错误的不确定性;MVC框架是个好东西,在使用它之前,很多.NET使用者也试图将表现层和控制层分离,并将控制层集中,只是一直没有找到好的解决方案,个人认为这与.NET的以事件为驱动的编程模型有些关系,这种模型使得控制层很难被分离成为单独一个有效的层。移植来的MVC框架解决了一部分的问题,但他依然有所限制,如果我们的表现层使用了一些第三方的控件,从而引入第三方的事件处理句柄和参数时,这些又会将模型、表现和控制层牢牢地结合在一起,使MVC框架失去了意义(这种理解方式为个人观点,但对第三方控件的依赖会使MVC框架失效这个结论是被认同的)。作为从java移植来的框架,Spring.net还有一个优势,就是Spring在java中有很多比较成熟稳定的与其他工具搭配使用的方式,而这些工具又有很多都有了.NET版本,这样对于熟悉java的人来说,上手就变得容易了很多,可以减少很多摸索的过程。
Spring.net是一种低侵入式的(它的有些子框架是无侵入式的,例如IOC框架)框架,被他管理的组件和服务不需要具备Spring.net的特征,因此只要这些组件的业务被合理设计,他们就可以在任何需要的地方使用,从而实现他们的重用性。这部分的功能是在IOC框架中完成的。反过来说,因为这种无侵入性,任何其他框架下的或者独立的组件都可以在Spring.net的IOC框架下被管理和使用,因此,Spring.net不但可以应用于新系统的开发,也同样适用于对旧有系统的整合。Spring.net的IOC框架支持上边提到的那三种依赖注入,但他比较推荐使用设值注入。如果所依赖的不是一个基本类型而是一个对象的话,框架支持自动查找装配,只要这个被依赖者也进行了配置,但这种做法并不被作者推荐,推荐的做法是手工在配置文件中建立关联关系。
Spring.net的AOP集成框架与其它的.NET AOP实现差不多,目前都还只能对具有Virtual修饰符的方法进行拦截,从而插入想要执行的代码。对于AOP,面向方面编程单从概念上讲比较难以理解,这方面比较典型的例子是记录日志。在一个系统中各种操作都需要记录日志,所以日志就是一个“方面”,传统的记录日志的方式一般是做一个公共的模块,由需要记录日志的组件来调用它,从设计上看,这需要建立起非常多的依赖关系,不符合低耦合的原则。而使用AOP则可以对这种情况进行解耦,它的做法是进行代码注入。将写好的记录日志的代码,使用配置文件“注入”到需要记录日志的方法中,注入的方式包括前置、后置和包围等。前置是将注入代码在方法前执行,后置是将注入代码在方法执行后执行,包围是在方法执行前执行一部分,然后再方法执行后再执行一部分,这种方式可以让我们联想到事务处理也是可以这样来做的!但是AOP也会带来一些问题,他降低了系统设计的可预见性,使得错误难以被发现且增加了新手上手的难度。
Castle的整体构建与Spring.net有很多相似,他同样是低侵入式的,由一系列可以独自运行的子框架组成。他目前使用的版本是Release Candidate 2。作为一个开源项目,它比较强调扩展性,目前他还只具备比较基本的功能,例如在自动类型转换功能中,它仅有基本类型和继承了IList接口的转换,如果需要新的类型转换,就需要用户自己定义一个转换器才可以。Castle主要包括以下几个组成部分:MicroKernel、Windsor、MonoRail、Aspect#、ActiveRecord,其中MicroKernel是IOC框架的核心,也是整个Castle框架的核心,Windsor是对MicroKernel的扩展,是一个真正适合使用的IOC框架,MicroKernel/Windsor是Castle的底层核心实现,它采用IoC容器对系统进行运行期动态设置,主要包括Facilities、Components、Services三大部分。MonoRail是Castle的MVC框架,它是Ruby on Rail的.Net实现,这是一个MVC Web框架,它与传统WebForm在控制上的不同在于WebForm采用页控制器模式,而MVC采用前端控制器模式。在界面表达方式上MonoRail采用模板引擎输出,模板引擎在PHP和JSP上已广泛使用,而在ASP.NET上因为服务端控件的强大功能和易用性而很少有人使用,两者是各有优缺点。Aspect#是Castle的AOP框架。除了自身提供的功能外,它还提供插件式的扩展,例如Nhibernate就被作为一个插件,可以在Castle中很方便地被使用。
MicroKernel和Windsor是Castle的IOC框架,通常使用的是Windsor。对于上边提到的3种注入方式,Windsor将设值注入和构造器注入作为一种来对待,同时对于类间的依赖,不需要在配置文件中体现,这种依赖框架会自动在配置文件中查找被依赖类的配置,然后自动建立关联关系。因此从这一点来看Castle的使用比Spring.net方便,但运行效率会低一些。
MonoRail也是一个从java移植来的MVC框架,被组合到Castle开源项目中。因此他也面对着和Spring.net 的MVC框架一样的问题。
ActiveRecord是构建于Nhibernate的数据访问工具,功能强大。不过Nhibernate发展多年,直接使用会更受欢迎一些。