没有IoC的年代
\一个简单的例子:
\\var Engine = require('./engine');\var Wheel = require('./wheel');\\var Car = function() {\ this.engine = new Engine();\ this.wheel = new Wheel();\}\\Car.prototype.run = function() {\ this.engine.run();\ this.wheel.run();\ console.log('run car...');\}\\module.exports = Car;\\
在例子中,汽车(car)需要依赖轮子(wheel)和发动机(engine)才能跑起来。为了处理好这一关系,必须首先人为的通过require把engine和wheel引入进来,然后通过new操作实例化,这样car才能真正的run起来。
\这个例子非常简单,但是存在着一些问题:
\- require的时候,需要直接知道engine和wheel的文件位置、文件名、以及所exports的是什么。一旦engine或者wheel的文件名、所在位置、exports方式发生了变化,require操作必须做出相应的改变\
- car直接依赖于engine和wheel,因此如果我们试图做单元测试,则会发现mock engine或者wheel非常困难,要么就是修改engine、wheel的代码,要么就是修改car的代码\
这个例子只有3个对象,读者可能觉得也没啥要紧的,这样直接做也没多大问题。但是一旦系统里面的对象数量变大了呢?复杂的依赖关系可能就是这样的:
\ \这样的系统紧密耦合,往往会造成难以维护、难以重构、难以做单元测试,尤其是当一个新人加入团队的时候,也会因为这份复杂性变得举步维艰,看不明白也改不动。
\步入IoC
\使用IoC之后,car的代码就会变成如下所示:
\\var Car = function(engine) {\ this.engine = engine;\ this.wheel = null;\}\\Car.prototype.run = function() {\ this.engine.run();\ this.wheel.run();\ console.log('run car...');\}\\module.exports = Car;\\
car无需知道engine、wheel的具体所在以require进来,也无需知道engine和wheel什么时候实例化以调用run方法跑起来,一切都变得如此简单与美好!
\- 去除了engine和wheel的直接依赖,随便engine和wheel叫什么名字,写在哪里(甚至可以是一个remote对象),重构变得轻而易举\
- 想对car进行单元测试,只需要依赖注入一个mock的engine和wheel对象即可完成,再也不需要直接修改car或者engine、wheel的代码了\
让IoC发挥作用
\本文通过Bearcat所提供的IoC容器来让IoC在Node.js中发挥作用。
\Bearcat IoC 使用非常简单,只需要提供一个简单的配置文件即可让IoC容器管理下的系统运转起来:
\\{\ \"name\": \"simple_inject\