01.渣男练成记:控制反转、依赖注入
小明今年20岁上大二,喜欢漂亮女孩,经过长达半年的马拉松式追求,终于俘获了聪明美丽的女孩小羽儿的芳心。两人天天腻歪在一起,一起上自习、吃饭、看电影、甚至kiss……更多的内容少儿不宜。总之,有个女朋友的感觉太好啦,小明已经彻底离不开小羽儿。代码实现如下:
复制 /**
* 小羽儿
*/
class XiaoYuEr {
constructor () {
this . name = " 小羽儿 " ;
}
study (){}
eat (){}
watchMovie (){}
kiss (){}
}
/**
* 小明
*/
class XiaoMing {
girlfriend = new XiaoYuEr () ;
constructor () {
this . name = " 小明 " ;
}
study () {
console . log ( ` ${ this . name } 和 ${ this . girlfriend . name } 在上自习 ` ) ;
this . girlfriend . study () ;
}
eat () {
console . log ( ` ${ this . name } 和 ${ this . girlfriend . name } 在吃饭 ` ) ;
this . girlfriend . eat () ;
}
watchMovie () {
console . log ( ` ${ this . name } 和 ${ this . girlfriend . name } 在看电影 ` ) ;
this . girlfriend . watchMovie () ;
}
kiss () {
console . log ( ` ${ this . name } 和 ${ this . girlfriend . name } 在接吻 ` ) ;
this . girlfriend . kiss () ;
}
}
let xiaoming = new XiaoMing () ;
xiaoming . study () ; // >>小明和小羽儿在上自习
xiaoming . eat () ; // >>小明和小羽儿在吃饭
xiaoming . watchMovie () ; // >>小明和小羽儿在看电影
xiaoming . kiss () ; // >>小明和小羽儿在接吻 幸福的日子持续了一年,小羽儿的父母想送她去美国留学,小明万般不舍,但是无奈贫贱不能移,只能看着女朋友离自己而去。伤心了几个月,好在小明长得酷酷的又有才气,很快有个漂亮的女孩小萌的喜欢上了他。于是……
有了新女友,小明很快走出了郁郁寡欢的日子。梅开二度看似美好,但其实小明没有那么爱小萌,这段恋情很快就结束了。然后某天,小明突然明白了,原来自己只是害怕孤独,需要有个大学女生陪伴自己上自习、吃饭、看电影……而已,至于具体是哪个女孩他并不特别在意。于是代码如下……
在编程的世界里,类A引用了某个类B,称为A“依赖”B。
上面这段代码,显示了小明从依赖具体 的女孩小羽儿,转为依赖抽象 的大学女生。这样之后,小明内心不用更换了女朋友的位置,因此没有心理包袱,感觉很轻松。然后第108行在构造函数里传递(注入)了具体的大学女生,这就叫做依赖(于)注入 (DI,Dependency Injection)。并且小明把选择女友的这种“控制权”让渡给了老天爷**(由JS引擎全局作用域的 showMeCollegeGirl 函数来分配女孩),这叫做 控制反转**(IoC**,**Inversion of Control), 通常用好莱坞原则“Don't call me ,I will call you”来比喻。
IoC 最核心的地方就是:在依赖方与被依赖方之间,也就是上文中说的小明与大学女生之间引入了第三方(也即老天爷),这个第三方统称为 IoC 容器。而IoC 容器,也就是实例化抽象类的地方。比如上面的例子,IoC容器老天爷通过生产showMeCollegeGirl函数来实例化多个大学女生。
anyway,这个渣男的例子比较丧 🤣 ,但是又的确是大多数男孩的成长历程,真实得可怕。我们要相信等小明再成熟一点儿,知道自己需要什么样的女孩陪伴终身之后,就会变成暖男的 😇 。
好了,我们继续接着来讲依赖倒置。
依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象,不要依赖于具体实现。简单的说就是要求针对抽象进行编程,不要对具体实现进行编程,这样就降低了与具体实现模块的耦合。
高层次模块不应该依赖低层次模块,它们都应该依赖于抽象。
前面小明的例子,他从依赖具体的某一个女孩,转为依赖一个更抽象的CollegeGirl类。而其他具体的女孩都继承并依赖抽象的CollegeGirl类。这种依赖关系的大变化,本来其他女孩都是被依赖的,现在反倒要依赖抽象的CollegeGirl,这体现了依赖关系的倒置。所以我们可以理解“依赖倒置”为依赖关系被改变。
03.何谓高层次,何谓低层次?
任何一个组织机构一定有架构的设计有职能的划分。按照职能的重要性,自然就有高低层次之分。并且,随着模块的粒度划分不同高层次与低层次模块会进行变动,也许某一模块相对于另外一模块它是低层次的,但是相对于其他模块它可能又是高层次的。
比如:公司组织架构里面,高层次有CEO、总裁、总经理,低层次依次有部门经理、职员。部门经理相对CEO来说是低层次的,部门经理相对职员来说又是高层次的。
再比如:软件分层架构里面,高层次是UI层,低层次依次有BLL(商业逻辑层),DAL(数据驱动层)。而BLL相对DAL来说是高层次的,BLL相对UI层来说又是低层次的。
抽象如其名字一样,是一件很抽象的事物。抽象往往是相对于具体而言的,具体也可以被称为细节,当然也被称为具象。
比如:
这是一位大学女生。大学女生是抽象,具体的小玉儿、小花等就是具体。
这是一幅画。画是抽象,而油画、素描、国画而言就是具体。
这是一件艺术品,艺术品是抽象,而画、照片、瓷器等等就是具体了。
交通工具是抽象,而公交车、单车、火车等就是具体了。
上面可以知道,抽象可以是物也可以是行为。具体映射到软件开发中,抽象可以是接口或者抽象类形式。