定义
所有做过.net、java或者php开发的人都应该听过依赖注入dependency injection(DI)或者inverse of control(IOC)控制反转,依赖注入是一种软件设计模式,它让人移除硬生生的写死的依赖关系,让人可以修改它们。依赖可以通过构造函数、定义方法或者设置属性来注入对象。
依赖注入好处
减小对象与依赖之间的藕合关系。
不需要对原代码进行修改,直接可以应用到当前代码。
有助于把客户与设计隔离开,减小设计改变带来的影响。
让系统不用修改当前代码就可以重新配置。
可以进行并行或者独立开发。
让代码更好维护和测试,因为用其他依赖包或者模版代替的话依赖的影响可以被消除。
依赖注入缺点
当要实例化一种类型,你必须要知道要用什么依赖。
隐藏了类型的实例化和依赖关系解释逻辑后,如果发生错误比较难查找问题。
要求你要写更多的代码。
可能会运行得更慢,因为要以新的关键字来实例化一种类型,把必须要用的相关的关键字对应解释实例化。
简单的依赖注入实现代码
以简单的买卖为例:
一单买卖,必须有买方和卖方参与
function Injector() { this.dependencies = {}; } Injector.prototype.register = function (key, value) { // 注册依赖 this.dependencies[key] = value; } Injector.prototype.resolve = function (deps, func, scope) { // 创建并解释注入依赖后的函数 var args = []; scope = scope || {}; for (var i = 0; i < deps.length, d = deps[i]; i++) { if (this.dependencies[d]) { scope[d] = this.dependencies[d]; } else { throw new Error('Can\'t resolve ' + d); } } return function () { func.apply(scope || {}, Array.prototype.slice.call(arguments, 0)); } } // 另一种写法,类require.js Injector.prototype.define = function (deps, callback) { // 创建并解释注入依赖 var args = []; for (var i = 0; i < deps.length, d = deps[i]; i++) { if (this.dependencies[d]) { args.push(this.dependencies[d]); } else { throw new Error('Can\'t resolve ' + d); } } if (typeof (callback)==='function') callback.apply(this, args); } var myInjector = new Injector(); var buy = function () { // 一个buy模块 this.name="Nelson"; this.start = function(){ document.writeln(this.name + ' bought some thing' + '<br>'); } } var sell = function () { // 一个sell模块 this.name='Jim'; this.start = function () { document.writeln(this.name + ' sold some thing' + '<br>'); } } myInjector.register('buy', new buy()); // 注册依赖模块 myInjector.register('sell', new sell()); // 注册依赖模块 var deal = myInjector.resolve(['buy', 'sell'], function (deal) { // 创建并解释注入依赖buy和sell后的函数 document.writeln(this.buy.name + '<br>'); this.buy.start(); document.writeln(this.sell.name + '<br>'); this.sell.start(); document.writeln(deal + ' relies on both ' + this.buy.name + ' and ' + this.sell.name + '<br><br>'); this.buy.name = 'Han Meimei'; this.sell.name = 'Li Lei'; }); deal("Deal"); console.log(myInjector); // 另一种写法 myInjector.define(['buy', 'sell'], function (b, s) { // 注入依赖buy和sell document.writeln('New Name: ' + b.name + '<br>'); b.start(); document.writeln('New Name: ' + s.name + '<br>'); s.start(); document.writeln('A deal relies on both ' + b.name + ' and ' + s.name + '<br>'); });