上一周,我们工作小组中有人问我一个问题:为什么DI(Dependency Injection,依靠性元插入的模式,这是编程中常用的一种模式)十分重要?现在许多编程人员采用OO(Object Oriented,目标编程)的方式。他们以为在一个class中定义数据和接口,将程序中的逻辑包含在其中就足够了。他们困惑地提出疑问,什么是DI,为什么还要采用DI模式?
第二天,我碰到单位中一位资深的编程员,我向他问了一个类似的问题,并问他具体怎么使用的。他说他只是在对原程序的测试中采用DI,在测试中假设有关读写数据库的变元,这样不会真正对数据库产生影响。这是测试中常用的方法,但这并不说明DI的全部。实际上,DI是一个非常重要的概念,而且是编程中常用的一种策略。
用一个形象的比喻,公司里IT部门需要采购部门购买一些硬件,IT按照要求将批准的单子交给采购部门,IT部门不感兴趣采购部门的谁去完成这个任务,也不需要了解,部门之间只需要按照之间的交接口进行联系和交流。DI编程模式就是按照这样的方式来编程,“部门”之间不需要知道谁在做具体的工作。
我回忆起我过去所写的许多项目,并查看我过去的程序。在这里我对此用一个简单的例子作具体的解释。先看看下面的一个C#例子:
public class MyDataReader {
...
public bool ReadData() {
var dbService = new MyDbService();
....
var data = dbService.GetObject();
....
}
}
上面有问题的地方是dbService变元由MyDbService class产生的一行,这种采用new来指定特定class的方式在编程中普遍存在。很明显MyDataReader class依赖于MyDbService class。换言之,MyDataReader知道所需要的dbService是从那一个class产生的。MyDataReader有必要知道具体创建的class吗?它只是使用一数据服务通过其接口取得数据(如GetObject()接口),它并不需要知道数据是如何取得的,那么它关心具体服务的class有必要吗?如果能够将这种依赖性分隔,让一个中介来提供一个数据服务变元,这样不就更好吗?
现在我们来看看下面改进的编码:
public class MyDataReader {
...
public bool ReadData() {
var dbService = DIContainer.GetInstance<IDBService>();
....
var data = dbService.GetObject();
....
}
}
这里只是一个小小的改动,DIContainer作为一个中介,通过它的接口GetInstance指定所需要的变元,这个变元具有抽象界面定义IDBService即可。DIContainer就像一个黑匣子,它知道如果根据要求的服务提供具体class的变元。这就是DI的典型应用例子。如果MyDataReader需要从不同的数据源取数据,将来MyDataReader根本不需要改动,只要告诉DIContainer即可。 这个服务元可能是从MyDbService,也可能是通过类似别的class如SqlDbService或OracleDbService。
现在有关DI的编程模式有许多,我个人认为,作为一个熟练的编程人员,应该学习和掌握这方面的知识,这样就可以写出更好、更干净、可维护和扩展的应用程序。在学习之前,首先要明白DI的道理,解决什么类型的问题,这样就容易理解DI的重要性和各种DI是如何解决这类问题的。如果你能熟练地运用DI技术,你的编程技术将会是高人一筹,而且如果你将来工作有这方面的要求,你将不会面对天书而一头雾水。
本文为我试图用万维网博客写技术方面(我在新浪博客上也做了成功的尝试)的一个尝试,万维网博客提供有限的界面,但提供源代码接口,这样就可以直接通过HTML码加入我所需要的基本功能。我今天写了一篇英文博客,以此为蓝本,我成功地复制成中文版的技术博文,编码带有不同的颜色,花的功夫不太大,这次尝试看来是成功的。 |