依赖注入:我所教的内容以及为什么我不明白这一点

时间:2016-04-13 20:15:11

标签: angular

我目前正在学习自己的Angular 2.我发现这段视频我觉得特别有用:https://www.youtube.com/watch?v=_-CD_5YhJTA

然而,关于依赖注入,Mosh在36:40开始的主题,我似乎并不完全理解他的论点。

即,他(在41:50)通过编写像这样的构造函数来说明

export class CoursesComponent {
    title = "The title of courses page";
    courses;

    constructor (courseService: CourseService) { 
        this.courses = courseService.getCourses();
    }
}

"我们写了一个不再与服务紧密耦合的组件" (引用)。

现在我试图让自己相信它是,但我看不出它是怎么回事。实际上,我们可以为此类的其他用法创建一个模拟服务CourseService。但是,构造函数中明确引用了一个在服务CourseService中定义的方法。在我看来,这显然不是以这种方式可重用(和可测试)的类。

写一些像

这样的东西会更有意义
constructor (courseService) { 
    this.courses = courseService;
}

然后让我们担心我们传递给其他地方的构造函数。然后,在我看来,我们诚实地脱离了服务。

但我是对的吗?或者我错过了这里的观点?而且,因为我是一个新手,但是如果我有一个观点,也许有人可以根据我关注的问题提出并选择写这门课程吗?

非常感谢。

威廉

4 个答案:

答案 0 :(得分:2)

我认为秘诀是你可以从main.ts中注入CourseService的不同实现(或者定义你的初始引导程序的任何文件)。

这是一个可行的例子

import {provide}    from 'angular2/core';

import {bootstrap}    from 'angular2/platform/browser';

import {AppComponent} from './app.component';

import {CourseService} from './course.service';
import {MyCourseService} from '../myImplementation/myCourse.service';

bootstrap(AppComponent, 
            [provide(CourseService, {useClass: MyCourseService})]);

我希望这会有所帮助

答案 1 :(得分:1)

我对Angular 2相当新,但我的理解是Angular 2有分层注入器,我当然可以看到构造函数类型在告诉Angular找到要使用的最接近的注入器祖先实例时很有用。使用courseService的子类可能会有好处,所以你 根据组件上下文,可以有不同的行为。

有关分层注射器的更多信息: https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html

答案 2 :(得分:1)

耦合将假定过度依赖服务。我想这不是这里的情况,因为Service有干净的界面 - getCourses()。我们可以使用IService{getCourses()}这样的不透明令牌更少耦合注入接口,这会使代码变得复杂并且使用起来不太方便,但是......

JavaScript允许我们在运行时模拟或提供不同的实现而不会出错(鸭子打字)。请检查此article

答案 3 :(得分:1)

除了@Piccis回答。

好莱坞原则(松耦合)

这里的主要内容类似于好莱坞原则。 “别打电话给我们,我们叫你”

如果你在课堂上使用new Xxx(),那将是非常紧密耦合:

export class CoursesComponent {
    title = "The title of courses page";
    courses;

    constructor () { 
        let courseService = new CourseService();
        this.courses = courseService.getCourses();
    }
}

但是使用您问题中的原始代码可以传入任何扩展CourseService 的类,并且还可以定义如何初始化此注入的实例(请参阅下一个代码剪切下文)。

扩展CourseService 的任何类都是由于TypeScript限制,其中接口在运行时不可用。

在Dart中,例如任何实现CourseService的类

配置依赖

class CourseServiceConfiguration {
  ...
}

class CourseService {
  constructor(private config:CouseServiceConfiguration) {}
  getCourses() { ... }
}

bootstrap(AppComponent, [
  CourseServiceConfiguration,
  CourseService]);

将提供CourseService的实例,其中配置了CourseServiceConfiguration

的实例

使用DI的其他键类型

如果仍然太紧,您可以使用其他键,例如stringOpaqueToken

bootstrap(AppComponent, [provide('courseService', {useClass: CourseService})]);

这样你可以像

那样注入它
export class CoursesComponent {
    title = "The title of courses page";
    courses;

    constructor (@Inject('courseService') courseService) { 
        this.courses = courseService.getCourses();
    }
}

但这样你就失去了类型检查和自动完成支持,因为courseService不是类型。 这种方式允许您在TypeScript中使用接口

export interface CourseService {
  getCourses();
}

export class CoursesComponent {
    title = "The title of courses page";
    courses;

    constructor (@Inject('courseService') courseService:CourseService) { 
        this.courses = courseService.getCourses();
    }
}

允许您注入implements CourseService的任何类型,并且仍然可以获得静态类型检查和正确的自动完成。

OpaqueToken类似于字符串键,但它可以防止具有冲突字符串的两个键仍然可以区分。在OpaqueToken中,字符串只是非正式的。