也谈依赖注入 — 从一个故事讲起(1)

JOJO 是 CPU 大学 CS 专业的一名学生。在入学时,JOJO 了解到这个学校有一些很奇怪的规则:

  1. 学生必须获得所有课程的学分才能毕业。
  2. 学生必须在报名并修完一门课程才能学习其他课程。
  3. 如果一门课程(后简称 课程 A)存在前置课程,并且此时没有获得前置课程的学分时,【课程 A】 教学中将自动添加所有前置课程的内容。
  4. 在第三条情况下完成的课程,仍然只获得此课程的学分。

“这 ** 不是坑爹呢?!”JOJO 想。“前置课程没学,教学中把前置课程的内容讲一遍倒是很合理,但是这第四条又说只给这门课的学分,那如果我排序错乱,岂不是一门课得学好几遍?”

CS 专业有三门课,C 语言(以下简称 C )、计算机组成原理(CCP)以及操作系统(OS)。其中:

  1. C 不需要前置课程
  2. CCP 依赖 C
  3. OS 依赖 C 和 CCP

JOJO 想,“很显然,想要不重复学习一门课程,就需要保证在学习某一门课程时,所有前置课程的学分我都拿到了。因而,很容易想到如下的简单算法。”


interface ICourse {

    name: string;

    preCourses: ICourse[];

}



type jojosBizarreAlgorithm = (course: ICourse) => void

const jojosBizarreAlgorithm: jojosBizarreAlgorithm = course => {

    course.preCourses.forEach(jojosBizarreAlgorithm)

    learnCourse(new Course(course.name))

}



const unfinishedCourses = OAA.getAllUnfinishedCourses()

while (unfinishedCourses.length) {

    const courseOfMostInterest = getMostInterestCourse(unfinishedCourses)

    jojosBizarreAlgorithm(courseOfMostInterest)

}
复制代码

回到依赖注入

JOJO 用这个算法顺利且省事的毕业了。让我们回到依赖注入这个点上。

让我们看以下的代码,实际上做的就是第三条和第四条规则所做的事情:如果在没有学习 C 和 CCP 的情况下,new 一个 OS 服务需要创建其依赖的 C 和 CCP。但是由于 C 和 CCP 都是在 OS 的构造函数内构造的,所以外部无法获得二者,仍然需要重新构造。

class Course {

    constructor(name: string) {

        // 构造需要的服务

        getAllPreCourses(name).forEach(

            preCourseName => new Course(preCourseName))

        // 自身的逻辑

        learn(name)

    }

}



new Course('os')
复制代码

在三个服务存在依赖的情况下就已经会出现如此多重复 new 服务的情况了。更不要说更加复杂的项目,几十个服务互相关联,想想都是灾难性的。依赖注入很重要的一个目的就是减少这种无意义的构造,每个课程不用去关注学习前置课程(构造依赖的服务),只需要考虑自己课程的学习(自身服务逻辑的编写)就可以了。

当然,在具体的开发中可没有人会手动向 course.preCourses 这样的数组中添加依赖,本文只是屏蔽了如何获得依赖的实现细节。如果想了解此部分,请耐心等待本文下一部分的内容。?

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享