使用Typescript实现依赖注入(DI)

时间:2022-09-23 19:05:24

前言
DI总是和ico相辅相成的,如果想对DI有更多的了解,可以移步我的另一篇文章 依赖注入(DI)和控制反转(IOC),再次我就不多做赘述了。

前几天看见一道面试题,今天借这个话题想跟大家分享一下:

为什么在实际开发中,我们总是用DI,而不是用工厂模式,工厂模式也能实现同样的效果

emmmm,想了一下,DI相当于是一种把当前对象和它所依赖的对象强解耦了,注入对象并不需要我们操心,而是把它委托给第三方,这个第三方可以是一些库或者框架,也可以是我们自己实现的ioc容器。而工厂模式,它是可以把我们需要的对象放进去,然后产生出我们最终需要的实例,但是创建这部分过程实际上还是由我们来做了。

Typescript依赖注入
javascript的动态类型,有时候会给我们带来很多的麻烦,实际上如果js能够在编译期就识别类型,那么性能会大大提升,比如webassembly。

typescript不一样,它是js的超集,它始终会先用tsc编译一遍,再转换为js运行,它始终是js,但是ts在编译期就检查类型,是可以让我们避免很多的错误的。如果想了解更多typescript请移步ts官网

typescript被很多框架所采用,比如angular,并且以它实现了依赖注入,我们在angular中,将一个类注册进ioc容器,只需给它附加一个injectable装饰器即可,比如:

@Injectable()
class User{
//...
}
1
2
3
4
在angular中,我们把用injectable装饰器修饰的类叫做service,我们可以在任何我们需要User类的时候,注入进来,比如:

class Main{
constructor(priavte user:User){

}
}
1
2
3
4
5
只需在构造函数的参数上写上对user的依赖,那么ioc容器就会帮助我们把user注入进来。

实现一个精简的DI
其实DI的具体实现并不是很复杂,现在我们来实现一个精简版的DI。

核心思想:根据类所声明的依赖,判断该依赖是否处于ioc容器中,如果处于,将它注入,并返回该类的实例,如果不属于,抛出一个异常,通知必须将依赖进行注册。

大致分为两部分:

​ 1.注册

​ 2.创建实例

先看看如何使用,再说具体实现

假如现在有A,B,C三个类

@Injectable()
class C{
constructor(){}
}

@Injectable()
class B{
constructor(private c:C){

}
}

@Injectable()
class A{
constructor(priavte b:B){}
}

//产生实例
let a:A = classFactory(A);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在A中声明对B的依赖,在B中声明对C的依赖。

每个类都用injectable装饰器进行装饰,实际上是把它们放进了ioc容器。

通过classFactory返回A的实例,此时b已经被注入进来了,同时c也已经注入进b,classFactory完成注入的动作。

下面看一下具体实现:

目录树

src
|-- index.ts
|-- ioc.ts
1
2
3
ioc.ts

//ioc容器
let classPool:Array<Function> = [];

//注册该类进入容器
export function Injectable(){
return (_constructor:Function) => {
let paramTypes:Array<Function> = Reflect.getMetadata('design:paramtypes',_constructor)
//已注册
if(classPool.indexOf(_constructor) != -1) return;
for(let val of paramTypes){
if(val === _constructor) throw new Error('不能依赖自己')
else if(classPool.indexOf(val) == -1) throw new Error(`${val}没有被注册`)
}
//注册
classPool.push(_constructor);
}
}

//实例化工厂
export function classFactory<T>(_constructor:{new(...args:Array<any>):T}):T{
let paramTypes:Array<Function> = Reflect.getMetadata('design:paramtypes',_constructor)
//参数实例化
let paramInstance = paramTypes.map((val:Function) => {
//依赖的类必须全部进行注册
if(classPool.indexOf(val) == -1) throw new Error(`${val}没有被注册`)
//参数还有依赖
else if(val.length){
return classFactory(val as any);
}
//没有依赖直接创建实例
else{
return new (val as any)();
}
})
return new _constructor(...paramInstance);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
index.ts

@Injectable()
class C{
constructor(){}
}

@Injectable()
class B{
constructor(private c:C){

}
}

@Injectable()
class A{
constructor(priavte b:B){}
}

//产生实例
let a:A = classFactory(A);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
为了验证DI的有效性,可以为C声明一个实例方法,比如

@Injectable()
class C{
constructor(){}

sayHello(){
console.log("hello")
}
}

@Injectable()
class B{
constructor(private c:C){

}

sayHello(){
this.c.sayHello();
}
}

@Injectable()
class A{
constructor(priavte b:B){
b.sayHello();
}
}

//产生实例
let a:A = classFactory(A);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
运行后

hello
1
参考:https://zhuanlan.zhihu.com/p/22962797
---------------------
作者:小辣抓
来源:CSDN
原文:https://blog.csdn.net/HaoDaWang/article/details/79776021
版权声明:本文为博主原创文章,转载请附上博文链接!

使用Typescript实现依赖注入(DI)的更多相关文章

  1. &lbrack;Android&rsqb;使用Dagger 2依赖注入 - DI介绍(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5092083.html 使用Dagger 2依赖注入 - DI介 ...

  2. 浅析&OpenCurlyDoubleQuote;依赖注入&lpar;DI&rpar;&sol;控制反转&lpar;IOC&rpar;”的实现思路

    开始学习Spring的时候,对依赖注入(DI)——也叫控制反转(IOC)—— 的理解不是很深刻.随着学习的深入,也逐渐有了自己的认识,在此记录,也希望能帮助其他入门同学更深入地理解Spring.本文不 ...

  3. 依赖注入&lpar;DI&rpar;和Ninject,Ninject

    我们所需要的是,在一个类内部,不通过创建对象的实例而能够获得某个实现了公开接口的对象的引用.这种“需要”,就称为DI(依赖注入,Dependency Injection),和所谓的IoC(控制反转,I ...

  4. 控制反转IOC与依赖注入DI

    理解 IOC  http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html IOC 相关实例      的http:// ...

  5. Atitit js中的依赖注入di ioc的实现

    Atitit js中的依赖注入di ioc的实现 全类名(FQCN)为标识符1 混合请求模式1 使用类内  builder  即可..2 Service locator method走ok拦2 Jav ...

  6. 控制反转&lpar;Ioc&rpar;和依赖注入&lpar;DI&rpar;

    控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...

  7. 控制反转IOC与依赖注入DI【转】

    转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...

  8. 依赖注入&lpar;DI&rpar;和控制反转&lpar;IOC&rpar;

    依赖注入(DI)和控制反转(IOC) 0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只 ...

  9. MVC进阶之路&colon;依赖注入&lpar;Di&rpar;和Ninject

    MVC进阶之路:依赖注入(Di)和Ninject 0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类, ...

  10. 依赖注入&lpar;DI&rpar;和Ninject

    [ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject 本文目录: 1.为什么需要依赖注入 2.什么是依赖注入 3.使用NuGet安装库 4.使用Ninject的一般步骤 5. ...

随机推荐

  1. javascript判断是否为闰年

    //判断年份year是否为闰年,是闰年则返回true,否则返回false function isLeapYear(year){ var a = year % 4; var b = year % 100 ...

  2. Submit Text 快捷键总结

    Ctrl+D : 选择单词,重复可增加选择下一个相同的单词Ctrl+F : 查找内容Ctrl+G : 跳转到指定行Ctrl+H : 替换    Ctrl+J : 合并行(已选择需要合并的多行时)Ctr ...

  3. 一句话概括下spring框架及spring cloud框架主要组件

    作为java的屌丝,基本上跟上spring屌丝的步伐,也就跟上了主流技术.spring *项目:Spring IO platform:用于系统部署,是可集成的,构建现代化应用的版本平台,具体来说当你 ...

  4. SQL Server数据库备份(本机)

    基础的SQL Server数据库备份存储过程 /**************************************************************************** ...

  5. 《how to design programs》12章函数复合

    我们写代码时要学会适应辅助函数.作者提出了一个问题,如何对一个表排序.排序函数读取一个表,产生另一个表.排序函数的合约和用途如下: (sort empty) ;; expected value: em ...

  6. 和Eclipse一起走过的日子

    一见钟情    大二上学期,第一次接触java Web.老师为了帮助我们从底层理解java Web的执行环境,要求我们不能使用不论什么IDE,仅仅能用记事本.    好吧,老师也是为了咱好.简单的一个 ...

  7. 关于ML&period;NET v0&period;6的发布说明

    ML.NET 0.6版本提供了几项令人兴奋的新增功能: 用于构建和使用机器学习模型的新API 我们主要关注的是发布用于构建和使用模型的新ML.NET API的第一次迭代.这些新的,更灵活的API支持新 ...

  8. 【转】配置不当引起高危漏洞?看加密货币交易所如何正确用Spring Boot Actuaotr框架

    https://xz.aliyun.com/t/2233 SpringBoot应用监控Actuator使用的安全隐患 概述 微服务作为一项在云中部署应用和服务的新技术是当下比较热门话题,而微服务的特点 ...

  9. Netty入门——客户端与服务端通信

    Netty简介Netty是一个基于JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞.基于事件驱动.高性能.高可靠性和高可定制性.换句话说,Netty是一个NIO框架,使用它可以简单快速 ...

  10. vscode 正则 计算代码全部有效行数;清除文件空行

    清除空行: 正则表达式:^\s*(?=\r?$)\n 计算全部代码行数: 正则表达式:b*[^:b#/]+.*

相关文章