面向对象一文搞定,终生难忘(面向对象心得)
574
2022-05-30
文章目录
简介
为什么要有 InversifyJS?
目标
安装
应用示例
步骤 1: 声明接口和类型
步骤 2: 使用 @injectable 和 @inject 装饰器声明依赖
步骤 3: 创建和配置容器
步骤 4: 解析依赖
拓展阅读
简介
InversifyJS ,一个强大又轻量的控制反转容器,提供给JavaScript 和 Node.js 应用使用,使用TypeScript编写。
InversifyJS 是一个轻量的 (4KB) 控制反转容器 (IoC),可用于编写 TypeScript 和 JavaScript 应用。 它使用类构造函数去定义和注入它的依赖。InversifyJS API 友好易懂, 鼓励对 OOP 和 IoC 最佳实践的应用.
为什么要有 InversifyJS?
JavaScript 现在支持面向对象编程,基于类的继承。 这些特性不错但事实上它们也是危险的。 我们需要一个优秀的面向对象设计(比如 SOLID),Composite Reuse等)来保护我们避免这些威胁。然而,面向对象的设计是复杂的,所以InversifyJS应运而生。
InversifyJS 是一个工具,它能帮助 JavaScript 开发者,写出出色的面向对象设计的代码。
目标
InversifyJS有4个主要目标:
允许JavaScript开发人员编写遵循 SOLID 原则的代码。
促进并鼓励遵守最佳的面向对象编程(OOP)和依赖注入(IoC)实践。
尽可能少的运行时开销。
提供艺术编程体验和生态。
安装
可以使用npm获得最新的版本和类型定义:
$ npm install inversify reflect-metadata --save
1
注:由于 InversifyJS 通过反射来获取装饰器的相关元数据,所以需要额外安装库
reflect-metadata。
Inversify npm 包已经包含了 InversifyJS 的类型定义
:警示: 重要! InversifyJS 需要 TypeScript 的版本 >= 2.0 还有
experimentalDecorators, emitDecoratorMetadata, types and lib 在 tsconfig.json 中 compilerOptions 的配置如下:
{ "compilerOptions": { "target": "es5", "lib": ["es6"], "types": ["reflect-metadata"], "module": "commonjs", "moduleResolution": "node", "experimentalDecorators": true, "emitDecoratorMetadata": true } }
1
2
3
4
5
6
7
8
9
10
11
inversifyjs需要现代JavaScript引擎,支持以下特性
Reflect metadata
Map
Promise (Only required if using provider injection)
Proxy (Only required if using activation handlers)
如果运行环境不支持这些特性,可能需要导入 shim 或 polyfill.
:警示: reflect-metadata polyfill 应该在您整个应用中只导入一次, 因为 Reflect 对象需要成为一个全局的单例。
应用示例
inversifyjs 基本用法和 API应用示例如下:
步骤 1: 声明接口和类型
目标是编写遵循依赖倒置原则的代码。
这意味着我们应该 ”依赖于抽象而不依赖于具体实现“ 。
先声明一些接口(抽象)。
// file interfaces.ts interface Warrior { fight(): string; sneak(): string; } interface Weapon { hit(): string; } interface ThrowableWeapon { throw(): string; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Inversifyjs 需要在运行时使用类型标记作为标识符。接下来将使用 Symbol 作为标识符,也可以使用类或字符串。
// file types.ts const TYPES = { Warrior: Symbol.for("Warrior"), Weapon: Symbol.for("Weapon"), ThrowableWeapon: Symbol.for("ThrowableWeapon") }; export { TYPES };
1
2
3
4
5
6
7
8
9
警示: 推荐使用 Symbol,但 InversifyJS 也支持使用类和字符串字面值。
步骤 2: 使用 @injectable 和 @inject 装饰器声明依赖
接下来,声明一些类,实现刚刚声明的接口。需要使用 @injectable 装饰器去注解。
当一个类依赖于某个接口时,我们需要使用 @inject 装饰器,来定义在运行时可用的接口标识。在这种情况下,将使用 Symbol, 如 Symbol.for("Weapon") 和 Symbol.for("ThrowableWeapon") 作为运行时的标识。
// file entities.ts import { injectable, inject } from "inversify"; import "reflect-metadata"; import { Weapon, ThrowableWeapon, Warrior } from "./interfaces" import { TYPES } from "./types"; @injectable() class Katana implements Weapon { public hit() { return "cut!"; } } @injectable() class Shuriken implements ThrowableWeapon { public throw() { return "hit!"; } } @injectable() class Ninja implements Warrior { private _katana: Weapon; private _shuriken: ThrowableWeapon; public constructor( @inject(TYPES.Weapon) katana: Weapon, @inject(TYPES.ThrowableWeapon) shuriken: ThrowableWeapon ) { this._katana = katana; this._shuriken = shuriken; } public fight() { return this._katana.hit(); } public sneak() { return this._shuriken.throw(); } } export { Ninja, Katana, Shuriken };
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
37
38
39
40
41
如果更喜欢使用属性注入而不是构造函数注入,那就可以不用声明类的构造函数了,属性注入方式如下:
@injectable() class Ninja implements Warrior { @inject(TYPES.Weapon) private _katana: Weapon; @inject(TYPES.ThrowableWeapon) private _shuriken: ThrowableWeapon; public fight() { return this._katana.hit(); } public sneak() { return this._shuriken.throw(); } }
1
2
3
4
5
6
7
步骤 3: 创建和配置容器
推荐在命名为 inversify.config.ts 的文件中创建和配置容器。这是唯一有耦合的地方。 在项目其余部分中的类,不应该包含对其他类的引用。
// file inversify.config.ts import { Container } from "inversify"; import { TYPES } from "./types"; import { Warrior, Weapon, ThrowableWeapon } from "./interfaces"; import { Ninja, Katana, Shuriken } from "./entities"; const myContainer = new Container(); myContainer.bind
1
2
3
4
5
6
7
8
9
10
11
12
13
步骤 4: 解析依赖
可以使用方法 get
import { myContainer } from "./inversify.config"; import { TYPES } from "./types"; import { Warrior } from "./interfaces"; const ninja = myContainer.get
1
2
3
4
5
6
7
8
正如我们所看到的,Katana and Shuriken 被成功的解析和注入进 Ninja。
InversifyJS 支持 ES5 和 ES6 ,而且可以在没有 TypeScript 环境下使用。
不做知识的搬运工,只做知识的汇聚者!
注:本文转载于https://doc.inversify.cloud/zh_cn/,学习InversifyJS,看此文足矣!!墙裂推荐!!
拓展阅读
InversifyJS【Github】
中文文档
Java JavaScript
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。