依赖注入

依赖注入

前面我们介绍了耦合解耦的方法,比如工厂模式解耦,今天我们重点学习依赖注入解耦。

首先我们需要理解的是注入和模拟是松散的关系。

如果一个对象的依赖项需要注入,而另外一个对象此时负责构建该对象。我们就把问题皮球提到了另外一层?的确如此,皮球必须止于某个地方,而这个地方是应用程序或者测试开始的地方。

依赖注入器可以为代码构建和注入完全成型的对象。

依赖注入还有一点需要提醒的是作用域的问题,也就是作用域通知注入器是创建一个新的实例还是重用以前的实例。对于这一点的话,对Java中Spring的bean的作用域有了解的应该不难理解。

我们来看下面的代码:

var SpaceShuttle = function() {
	this.mainEngine = new SpaceShuttleMainEngine();
 	this.boosterEngine1 = new SpaceShuttleSolidRocketBooster();
 	this.boosterEngine2 = new SpaceShuttleSolidRocketBooster();
 	this.arm = new ShuttleRemoteManipulatorSystem();
}

上面的代码在构造函数中存在很多依赖项,因此在测试的时候需要模拟出来,很不方便。看看下面这种实现方式。

var SpaceShuttle = function(mainEngine, b1, b2, arm) {
	this.mainEngine = mainEngine;
 	this.boosterEngine1 = b1;
 	this.boosterEngine2 = b2;
 	this.arm = arm;
}

这样修改了之后,构造函数不在依赖哪些对象,而是可以通过注入的方式实例化这个对象。

var knit = require('knit');
knit.config(function(bind){
	bind('MainEngine').to(SpaceShuttleMainEngine).is('constructor');
	bind('BoosterEngine1').to(SpaceShuttleSolidRocketBooster).is('constructor');
	bind('BoosterEngine2').to(SpaceShuttleSolidRocketBooster).is('constructor');
	bind('Arm').to(ShuttleRemoteManipulatorSystem).is('constructor');
	bind('ShuttleDisvovery').to(SpaceShuttle).is('constructor');
	bind('ShuttleEndeavor').to(SpaceShuttle).is('constructor');
	bind('Pad').to(new LaunchPad()).is('constructor');
});

注意,这里的实现类是在其他地方定义的,比如:

var SpaceShuttleMainEngine = function(){
}

每当请求MainEngine时,knit就会将该对象的实例填充到:

var SpaceShuttle = function (MainEngine, BoosterEngine1, BoosterEngine2, Arm) {
	this.mainEngine = MainEngine;
}

所以,knit.inject方法里的整个SpaceShuttle对象和它的所有依赖对象都可用。

举个例子

knit.inject(function(ShuttleDiscovery, ShuttleEndeavor, Pad){
	ShuttleDiscovery.blastOff(Pad);
	ShuttleEndeavor.blastOff(Pad);
});

如果我想替换某一个具体的实现,我只需要在配置中替换成最新的一个类即可,这样可以方便的在不同版本的实现类,以及不同的环境中进行替换。举个例子

bing('Arm').to(MexicanShuttleRemoteManipulatorSystem).is('constructor');

上面的代码将Arm的注入替换成了另外一个实现类,这种替换对于我们的测试是相当方便的。

 

 

 

 

版权声明:著作权归作者所有。

thumb_up 0 | star_outline 0 | textsms 0