在 Angular 中 Dependency Injection 是个非常大的特点,Dependency Injection 是一种设计模式,主要是用於将相关的程序由外部注入进 component 中
而不是在 component 中创建以实现解耦
的目的,可以有效地减低维护的复杂度。
Coupling(藕合) 又可以称为 Dependency(依赖),简单来说就是程序与程序之间互相具有依赖性,在一个专案中如果彼此的依赖性越高则代表越难维护
。
一般在开发专案时会将功能相关的部分结合起来作为一个 Class 以提供给其他地方使用,当某个地方需要使用到这个 Class 实则需要再对应的地方使用关键字 new
产生一个新的物件,这样才可以使用到里面的 method
或 property
,来举个例子某一个国小的教室 (ClassRoom) 需要一个老师,老师的功能有 Teaching
, Test
, QA
这三种功能。
class MathTeacher {
constructor() { }
Teaching() {
console.log('Teach Math');
}
Test() {
console.log('Test 1 + 1 = 2');
}
QA() {
console.log('QA Time');
}
}
而现在的情境是在这个教室中有一个数学老师在执行这三种功能并执行它
class ClassRoom {
mathTeach = new MathTeacher();
ClassTeaching() {
this.mathTeach.Teaching();
}
ClassTest() {
this.mathTeach.Test();
}
ClassQA() {
this.mathTeach.QA();
}
}
room = new ClassRoom();
room.ClassTeaching();
room.ClassTest();
room.ClassQA();
虽然这种写法可以完成目标但如果今天需要将数学老师变为英文老师的话,那就需要将 mathTeach = new MathTeacher();
这边更改为 englishTeacher = new EnglishTeacher();
,这种因为一个程序变动而导致另一个程序也需要随之修改的行为就称为高藕合(Coupling)
,如果专案很大的话这种高耦合会让专案的维护与开发变得越来越困难。
为了减轻每个程序中互相的依赖,这时就诞生了 Dependency Injection 这种设计模式,他主要的目的是通过将有关连的程序利用注入的方式由外部注入至需要的程序,而不是像过去一样在内部创建,而达成 DI 有两种方法
首先跟刚刚一样,新增一个Teacher 的 class (老师类别),将老师的技能 (Methods) 写入,可以随需求更改教学的内容。
class Teacher {
constructor() { }
Teaching() {
console.log('Teach Math');
}
Test() {
console.log('Test 1 + 1 = 2');
}
QA() {
console.log('QA Time');
}
}
接着对 ClassRoom Class 中修改 constructor 让需要授课的老师 class 由外部注入进来
class ClassRoom {
constructor(private teacher: Teacher) {} // (1)
ClassTeaching() {
this.teacher.Teaching();
}
ClassTest() {
this.teacher.Test();
}
ClassQA() {
this.teacher.QA();
}
}
接着使用这个新的 Room Class
const teach = new Teacher(); // (1)
const room = new ClassRoom(teach); // (2)
room.ClassTeaching();
room.ClassTest();
room.ClassQA();
除了在 constructor 中宣告注入的 Class 之外,还可以利用 setter
做到相同的功能。
class ClassRoom {
private _teacher!: Teacher
constructor() {}
set setTeacher(teacher: Teacher) { // (1)
this._teacher = teacher;
}
ClassTeaching() {
this._teacher.Teaching();
}
ClassTest() {
this._teacher.Test();
}
ClassQA() {
this._teacher.QA();
}
}
setter
用於将外部依赖的 Class 注入进来const teach = new Teacher(); // (1)
const room = new ClassRoom(); // (2)
room.setTeacher = teach; // (3)
room.ClassTeaching();
room.ClassTest();
room.ClassQA();
ClassRoom
中的 setter
将外部依赖的 Class (Teacher) 注入当使用了 Dependency Injection 这种设计模式後,你想要从数学老师变更为英文老师的话,只需要在 Teacher
Class 中更改教学方式就好,其他都不用变就可以达到目的,可以打幅度的减低维护的成本
class Teacher {
constructor() {}
Teaching() {
console.log("Teach English");
}
Test() {
console.log("Test A, B, C");
}
QA() {
console.log("QA English Time");
}
}
Dependency Inversion Principle:依赖反转,又称为依赖反向或依赖倒转
当专案越来越大的时候,就需要比 Dependency Injection 更有弹性的设计模式的出现,接着我们把上面的例子改一下,现在我们从一间教室变成多间,一位老师也变成多位老师且每个老师都用相同的方法但不同的内容教课,可能想一想就会觉得非常的复杂,不过没关系我们可以把他整理一下
要每一个 Class 都有着相同的格式的最好方法就是建立一个 interface 去规定需要哪些教学方式( method )
interface NormalSchool {
Teaching: () => void; // 教学
Test: () => void; // 考试
QA: () => void; // 提问
}
可以建立多个不同老师 ( Class ),透过 implements
将 interface
让每个老师 ( Class ) 有相同的教学模式 ( methods )。
class MathTeacher implements NormalSchool {
Teaching() {
console.log('Teach Math');
}
Test() {
console.log('Test 1 + 1 = 2');
}
QA() {
console.log('Math QA Time!')
}
}
class EnglishTeacher implements NormalSchool {
Teaching() {
console.log('Teach English');
}
Test() {
console.log('Test A, B, C, D');
}
QA() {
console.log('English QA Time!')
}
}
class JavascriptTeacher implements NormalSchool {
Teaching() {
console.log('Teach Javascript');
}
Test() {
console.log('Test program');
}
QA() {
console.log('program QA Time!')
}
}
修改 ClassRoom 我们把外部注入的对象这定为只接受去过师范大学的老师才可以进入这个教室
class ClassRoom {
constructor(private _teacher: NormalSchool) {} // 外部注入的对象必须是 NormalSchool
classTeaching() {
this._teacher.Teaching();
}
classTest() {
this._teacher.Test();
}
classQA() {
this._teacher.QA();
}
}
3间教室指定老师使用师范大学的教学方式,去教自己专业科目的内容。
const mathTeacher = new MathTeacher(); // Create math teacher
const englishTeacher = new EnglishTeacher(); // Create english teacher
const javascriptTeacher = new JavascriptTeacher(); // Create javascript teacher
const room1 = new ClassRoom(mathTeacher); // 将数学老师放入教室 1
const room2 = new ClassRoom(englishTeacher); // 将英文老师放入教室 2
const room3 = new ClassRoom(javascriptTeacher); // 将 Javascript 老师放入教室 3
room1.classTeaching();
room2.classTest();
room3.classQA();
上面的结果可以发现每间教室可以接受不同的老师,只要是从师范大学中出来的 ( implements NormalSchool ) 就可已放入,并且每个不同的老师都有着相同的教学方式 ( methods ) 但教授的内容却是不同的,之後如果某个教室需要更换老师或是需要新增一个新的老师,其他部分就不需要更改也不会受到影响,这就是 Dependency Inversion Principle
。
本章介绍了什麽是 Dependency Injection 的概念与在 Typescript 中如何实现,在我刚接触 Angular 的时候对於 Dependency Injection 来说可以说是一头雾水,只知道只要在 Constructor 里面宣告就可以用了,但根本不知道这麽做的目的是什麽,直到我去看了 Jun 大大对於 Dependency Injection 的一些概念与举例所以才比较明白是什麽,不过 Jun 大大的文章是用 Java 写的,所以本章算是把 Jun 大大的文转换为 Typescript 做个纪录,大家可以去看 Jun 大大原本的文章或是其他文章,都写得非常好!
<<: JS [撞墙] document.querySelector("").checked
我们今天来聊聊TensorFlow运算的几个较为常用的方法,不像其他语言的加减乘除,TensorFl...
本系列文章同步发布於笔者网站 我们在前几篇文章介绍了 NIST 对云端的定义,从今天开始文章将会进入...
这篇我们接着做: 取得网页上栏位资料 资料送往後台 资料写回资料库 取得栏位资料 在送资料到後台之前...
该文章同步发布於:我的部落格 在我一开始学习写 Rails 测试时,会有很常见的问题,就是到底什麽...
经过昨天的内容,读者们应该对於网页的渲染流程有大致的理解了。 我们再小小复习一下,大致上网页的渲染...