在此依赖注入示例中,控制反转出现在哪里?

Where does Inversion of Control arise during this example of Dependency Injection?

我完全糊涂了。关于依赖注入和控制反转的定义,有许多来源相互矛盾。这是我的理解要点,没有太多额外的细节,在大多数情况下让事情对我来说更复杂:依赖注入意味着我的函数不是召唤所需的依赖,而是将依赖作为参数提供。控制反转意味着,例如,当您使用一个框架时,它是调用您的用户区代码的框架,并且控制被反转,因为在 'default' 情况下,您的代码将调用库中的特定实现。

现在据我了解,不知何故,因为我的函数不再让人联想到依赖关系,而是将其作为参数,当我像下面这样使用依赖注入时,控制反转神奇地发生了。

所以这里是我为自己写的一个愚蠢的例子来围绕这个想法:

getTime.js

function getTime(hour) {
  return `${hour} UTC`
}

module.exports.getTime = getTime

welcome.js

function welcomeUser(name, hour) {
  const getTime = require('./time').getTime
  const time = getTime(`${hour} pm`)

  return(`Hello ${name}, the time is ${time}!`)
}

const result = welcomeUser('Joe', '11:00')
console.log(result)

module.exports.welcomeUser = welcomeUser

welcome.test.js

const expect = require('chai').expect
const welcomeUser = require('./welcome').welcomeUser

describe('Welcome', () => {
  it('Should welcome user', () => {
    
    // But we would want to test how the welcomeUser calls the getTime function
    expect(welcomeUser('Joe', '10:00')).to.equal('Hello Joe, the time is 10:00 pm UTC!')

  })
})

现在的问题是getTime函数的调用是在welcome.js函数中实现的,无法被测试拦截。我们想做的是测试 getTime 函数是如何被调用的,但我们不能这样做。 另一个问题是 getTime 函数几乎是硬编码的,所以我们不能模拟它,这可能很有用,因为我们只想单独测试 welcomUser 函数,因为这是单元测试的使用(getTime 函数例如,可以同时实施)。

所以主要的问题是代码是紧密耦合的,它更难测试,而且到处都是破坏。现在让我们使用依赖注入:

getTime.js

function getTime(hour) {
  return `${hour} UTC`
}

module.exports.getTime = getTime

welcome.js

const getTime = require('./time').getTime

function welcomeUser(name, hour, dependency) {
  const time = dependency(hour)

  return(`Hello ${name}, the time is ${time}!`)
}

const result = welcomeUser('Joe', '10:00', getTime)
console.log(result)

module.exports.welcomeUser = welcomeUser

welcome.test.js

const expect = require('chai').expect
const welcomeUser = require('./welcome').welcomeUser

describe('welcomeUser', () => {
  it('should call getTime with the right hour value', () => {
    
    const fakeGetTime = function(hour) {
      expect(hour).to.equal('10:00')
    }

    // 'Joe' as an argument isn't even neccessary, but it's nice to leave it there
    welcomeUser('Joe', '10:00', fakeGetTime)
  })

  it('should log the current message to the user', () => {
    
    // Let's stub the getTime function
    const fakeGetTime = function(hour) {
      return `${hour} pm UTC`
    }

    expect(welcomeUser('Joe', '10:00', fakeGetTime)).to.equal('Hello Joe, the time is 10:00 pm UTC!')
  })
})

据我了解,我上面所做的是依赖注入。多个消息来源声称,如果没有控制反转,依赖注入是不可能的。但是控制反转在哪里出现?

还有常规的 JavaScript 工作流程,您只需全局导入依赖项并稍后在您的函数中使用它们,而不是在函数内部要求它们或将其作为参数提供给它们?

查看 Martin Fowler 关于 IoC 和 DI 的文章。 https://martinfowler.com/articles/injection.html

IoC:非常通用的词。这种反转可以通过多种方式发生。

DI:可以看成是这个通用词IoC的一个分支。

所以在你的代码中,当你具体实现 DI 时,有人会说你的代码在 DI 的风格中具有这种 IoC 的一般概念。真正相反的是,寻找行为的默认方式(默认方式是在方法中编写它,相反的方式是从外部注入行为)。