换了新公司,公司的项目中有用到Castle,第一次接触,便去了解了一下,其下有很多的子项目,感觉很强大,值得深入的学习。Castle官网:http://castleproject.org/。园子里介绍Castle的文章也很多,推荐两个:http://terrylee.cnblogs.com/archive/2006/04/28/castl_ioc_article.html,http://www.cnblogs.com/wj/archive/2005/06/22/179357.html。园子里这些大牛们写这些文章都是05年左右的,到现在Castle也是发生了不少的变化,例如代码的方式,像其中简单例子中将组件加入IOC容器方法,但是其中涉及的思想或者思路还是一样的。
最先了解的就是称之为.net和silverlight可用的成熟的IOC容器的Windsor Container.Windsor是什么,Windsor是IOC容器。理解了IOC,那Windsor能在我们项目中起什么作用,我们什么时候要用到它,这些就不在是问题了。什么是IOC呢??大牛们同时指向了一篇文章:Inversion of Control Containers and the Dependency Injection pattern。谁写的,就不说了,早就听说过大名,甚至还拜读过大作,但不熟。E文的,还老长,耐着性子看了个半截,一个感受:E文不好害死人啊,我把N多年的E文学习80%都还给社会了。靠着仅有的语感和救命的一篇文章:http://www.cnblogs.com/yycilpppp/archive/2007/01/08/615011.html,才让我对IOC的概念似乎有些懂了。
IOC,翻译来就是控制反转,其实理解成为控制转移才更贴近实际,也就是控制权的转移。Martin Fowler所说的:不是说你说你用了IOC,你的项目就很NB了,IOC是框架的基本特征。例如我们.net的开发网站用到的web form框架,从用户请求网页开始,控件权在框架手中,但是本身框架提供很多供我们开发的接口、扩展,例如我们在Page_Load中写了一些代码,这其中就有IOC的概念,执行到Page_Load时,控制权就从框架转移到了我们代码里,我们的代码就可以控制整个的或者部分的执行了,执行完毕之后,再次返还给框架,框架再去负责运行其它的要运行的东西。
这样做有什么好处呢,就像是前面所说的web form,我们利用web form,你可以写你的逻辑,我可以写的逻辑,如果没有这个东西,那从整个请求开始运行什么都要我们去执行,那后果。。。。但是映射到我们的项目中,我们又不开发框架,我们用的着吗??就像框架,我们做的项目,你可以很容易的像在网页中写Page_Load那样轻易的替换你需要变更的逻辑,那不是可以很轻易的面对一些需求的变化了吗。装B的说就是脱耦。
为什么Castle Windsor/spring等等符合IOC的理念,它们主要解决什么问题呢?因为他们转移一些控制权到自己手里,它们接管了对象的创建、销毁等的控制权。他们是为了解决项目中组件的相互依赖问题的,他们要达到的目的就是可以在运行中替换组件,也就是所说的以插件的方式运行。所说来就是我们只负责编写负责各个职责的模块,而各个模块的依赖关系则交给我们的IOC容器去实现或者按照我们的配置由IOC去实现了。怎么个实现法,Windsor是利用自动装配,自动装配怎么实现的,研究windsor的源码吧,这里没有本事说清。和框架的IOC不一样,像windsor这种IOC的方式被取名叫做Dependency Injection 依赖注入。
依赖注入又分三种:构造注入,设置注入,接口注入。
举例说明:
1,构造注入:构造函数中设置要引用的对象
class LogHelper { private LogWriter _log; public LogHelper(LogWriter log) { _log = log; } }
2,设置注入
class LogHelper { private LogWriter _log; public void SetLogWriter(LogWriter log) { _log = log; } }
3,接口注入
class LogHelper { private ILog _log; public LogHelper(ILog log) { _log = log; } }
我们可以看到,这些都是为了降低组件间的耦合,可以让我们代码时获得更大的灵活性。
举个windsor应用的简单例子,只有调用时的代码。
// 调用1 LogHelper log = new LogHelper(new UserLog()); log.WriteLog("some error happen in user system."); // 调用2 IWindsorContainer container = new WindsorContainer(); container.Register(Component.For<ILog>().ImplementedBy<UserLog>().Named("userlog")); container.Register(Component.For<LogHelper>().Named("helper")); LogHelper log2 = (LogHelper)container.Resolve<LogHelper>("helper"); log2.WriteLog("some error happen in user system from ioc.");
其中UserLog实现了ILog,这个例子不足以说明IOC怎么实现了以插件的形式工作的,但是我们可以从log2的调用中看到,在调用2中我们并没有调用LogHelper的构造函数,我们只是从容器中取出我们想要的对象,Castle就自动的为我们实现我们想要的一切。调用1,依赖于UserLog()这个具体的实现,而调用2,如果对上述代码进行改造,装入和取出分离开,再改变下装入的方式,就可以实现我们调用只要去请求IOC容器就行了。至于这些IOC容器的更深入的使用,大牛的文章或者Castle官网去吧。
当然依赖注入并不是消除依赖实现以插件方式运行的唯一方法,Service Locator就是可替代的方法之一。这个不了解,暂不发言。
初步的理解,可能会有很多出入,欢迎大家给指点指点。