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

前言

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{//...
}

在angular中,我们把用injectable装饰器修饰的类叫做service,我们可以在任何我们需要User类的时候,注入进来,比如:

class Main{constructor(priavte user:User){}
}

只需在构造函数的参数上写上对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);

在A中声明对B的依赖,在B中声明对C的依赖。

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

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

下面看一下具体实现:

目录树

src|-- index.ts|-- ioc.ts

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);
}

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);

为了验证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);

运行后

hello

参考:https://zhuanlan.zhihu.com/p/22962797

使用Typescript实现依赖注入(DI)相关推荐

  1. 依赖注入(DI)和Ninject,Ninject

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

  2. 依赖倒置(DIP),控制反转(IoC)与依赖注入(DI)

    DIP,IoC与DI概念解析 依赖倒置 DIP(Dependency Inversion Principle) DIP的两大原则: 1.高层模块不应该依赖于低层模块,二者都应该依赖于抽象. 2.抽象不 ...

  3. 控制反转(Ioc)和依赖注入(DI)

    控制反转IOC, 全称 "Inversion of Control".依赖注入DI, 全称 "Dependency Injection". 面向的问题:软件开发 ...

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

    为什么80%的码农都做不了架构师?>>>    1. IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最 ...

  5. PHP依赖注入(DI)和控制反转(IoC)详解

    这篇文章主要介绍了PHP依赖注入(DI)和控制反转(IoC)的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 首先依赖注入和控制反转说的是同一个东西,是一种设计模式,这种设计模式用来减少程 ...

  6. Java依赖注入 - DI设计模式示例教程

    Java依赖注入 - DI设计模式示例教程 Java依赖注入 设计模式允许我们删除硬编码的依赖项,并使我们的应用程序松散耦合,可扩展和可维护.我们可以在java中实现依赖注入,以将依赖项解析从编译时移 ...

  7. [Android]使用Dagger 2依赖注入 - DI介绍(翻译)

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

  8. ioc控制反转_深入理解依赖注入(DI)和控制反转(IOC)

    转载本文务必须注明出处.微信号(Yemeir_com).以及添加原文链接. 为什么要使用依赖注入 使用依赖注入(DI)可以使控制者与抽象实现者松耦合,便于单元测试.通过控制反转(IOC)的设计原理来减 ...

  9. 依赖注入(di)模式_Java依赖注入– DI设计模式示例教程

    依赖注入(di)模式 Java Dependency Injection design pattern allows us to remove the hard-coded dependencies ...

最新文章

  1. 如何让PHP以root权限执行系统命令
  2. javascript有用小功能总结(未完待续)
  3. 第一篇:SpringCloud 构建微服务系统之服务注册和发现(consul)
  4. htmlplay前端编辑器下载_2019年最好用的代码编辑器推荐
  5. 笨方法“学习python笔记之函数
  6. HTML+CSS制作Windows启动加载动画
  7. 高级版本 【多后台】
  8. 中国海洋大学第四届朗讯杯高级组 A 2718 Rocky(模拟)
  9. webserver/CGI
  10. svn中文语言安装包使用
  11. 《我是一只IT小小鸟》阅读笔记
  12. python 更新pip报错 解决方法大全
  13. Sniffer报文捕获解析
  14. 淘宝美工掌握这4种能力,不逊色于UI设计师
  15. Kaggle泰坦尼克号比赛项目详解
  16. Python计算思维训练——数组和曲线绘制练习(三)
  17. 十、什么是临界资源及如何访问临界资源
  18. pikachu XSS Cross-Site Scripting(皮卡丘漏洞平台通关系列)
  19. mysql 表分区、按时间函数分区、删除分区、自动添加表分区
  20. java万年历方法_利用java制作万年历

热门文章

  1. 华为发布下一代智能产品战略及全新+AI系列新品!
  2. 【号外】腾讯和阿里股价齐飞 中国互联网进入蓝筹时代
  3. STM32和ST-LINK V2的连接与调试
  4. java.lang.IllegalArgumentException: No enum constant org.apache.ibatis.type.JdbcType.INT
  5. 奔向三张,不破不立:一个iOS开发工程师的职业规划思考(转自iOSer 逆,以资激励)
  6. 基于Q-learning的无人机三维路径规划(含完整C++代码)
  7. 使用 js 将图片进行转Base64转码
  8. i.MX RT开发笔记-01 | 初识 i.MX RT1062 跨界MCU
  9. Google Adwords关键词广告须注意的7个问题
  10. 2019年大数据发展趋势预测,该学什么编程语言?