我目前正在学习自己的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;
}
然后让我们担心我们传递给其他地方的构造函数。然后,在我看来,我们诚实地脱离了服务。
但我是对的吗?或者我错过了这里的观点?而且,因为我是一个新手,但是如果我有一个观点,也许有人可以根据我关注的问题提出并选择写这门课程吗?
非常感谢。
威廉
答案 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的其他键类型
如果仍然太紧,您可以使用其他键,例如string
或OpaqueToken。
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
中,字符串只是非正式的。