前端IOC控制反转与DI依赖注入并以didi JS DI库以及diagramJS插件机制(基于DI实现)
先回顾一下Java SpringBoot中涉及的IOC与DI:
SpringBoot中IOC&DI
Why:
以SpringMVC的web的Service与DAO层代码
为例,依赖耦合程度过高
。
How:
常见的解耦方式就是有个中间层,将信息交给中间层管
。
IOC(Inversion of Control)控制反转
- 业务层要用数据层的类对象,以前是自己
new
的- 现在自己不new了,交给
别人[外部]
来创建对象别人[外部]
就反转控制了数据层对象的创建权- 这种思想就是控制反转
依赖关系如何保注入
?
DI(Dependence Injection):依赖注入
前端中IOC与DI
DI实现库—— didid库
什么是依赖注入?
依赖注入是一种设计模式,它将对象的创建和依赖关系的管理从业务逻辑中分离出来。它有两个核心概念:
- 依赖注入模式:通过构造函数或方法参数显式传递依赖关系
- 依赖注入框架:自动管理对象创建和依赖关系
为什么要使用依赖注入?
- 显式依赖:通过构造函数参数明确依赖关系,便于理解
- 代码复用:解耦具体实现,更容易在不同环境中重用
- 易于测试:可以单独测试对象,无需整个环境
示例
var Car = function(engine) {this.start = function() {engine.start();};
};var module = {'car': ['type', Car],'engine': ['factory', createEngine]
};var injector = new di.Injector([module]);
injector.invoke(function(car) {car.start();
});
核心概念
- 模块:定义如何创建对象的配置对象
- 注入器:根据模块配置
创建和管理对象
(IOC容器) - 类型注册:
type
:通过构造函数创建实例factory
:通过工厂函数创建实例value
:直接使用固定值
使用场景
- Web 应用:使用数组表示法避免压缩问题
- 大型应用:管理复杂的依赖关系
- 测试环境:轻松mock依赖
与其他框架的区别
- node-di:增加了数组表示法和ES6支持
- Angular DI:更轻量,没有全局模块注册
依赖注入是构建可维护、可测试应用的重要模式,didi 是一个轻量级的实现
,适合各种JavaScript应用。
DiagramJS中的依赖注入
在 diagram-js 中,插件(或模块)是通过依赖注入(Dependency Injection, DI)机制
进行管理的。 didi
是一个轻量级的 JavaScript DI 框架,负责解析模块之间的依赖关系并进行实例化
。
每个模块可以定义以下属性:
- depends:声明该模块依赖的其他模块。
- init:指定在初始化时需要执行的服务名称。
服务名称: 以 [ 'type', 构造函数 ]
的形式注册服务
插件化架构
bpmn-js
是一个基于 diagram-js
构建的 BPMN 2.0 渲染和建模工具,它通过 didi
实现了插件机制,提供了灵活的模块化扩展能力。(GitHub)
🧩 插件机制概览
在 diagram-js
中,插件(或模块)是通过依赖注入(Dependency Injection, DI)机制进行管理的。 didi
是一个轻量级的 JavaScript DI 框架,负责解析模块之间的依赖关系并进行实例化。
每个模块可以定义以下属性:
__depends__
:声明该模块依赖的其他模块。__init__
:指定在初始化时需要执行的服务名称。服务名称
: 以[ 'type', 构造函数 ]
的形式注册服务。(bpmn.io Forum)
例如,创建一个简单的日志插件:
const MyLoggingPlugin = function(eventBus) {eventBus.on('element.changed', function(event) {console.log('Element changed:', event.element);});
};MyLoggingPlugin.$inject = ['eventBus'];export default {__init__: ['myLoggingPlugin'],myLoggingPlugin: ['type', MyLoggingPlugin]
};
在上述代码中,$inject
是 didi
用于指定依赖项的方式,确保在代码压缩后依赖关系仍然正确。 (bpmn.io Forum)
🔌 在 bpmn-js 中集成插件
要将自定义插件集成到 bpmn-js
中,可以在创建 BpmnJS
实例时,通过 additionalModules
选项添加插件模块:(bpmn.io Forum)
import BpmnJS from 'bpmn-js/lib/Modeler';
import MyLoggingModule from './my-logging-module';const bpmnModeler = new BpmnJS({container: '#canvas',additionalModules: [MyLoggingModule]
});
这样,bpmn-js
会在初始化时加载并执行你的插件模块。
🧪 示例:监听元素更改事件
以下是一个完整的插件示例,它监听元素的更改事件并在控制台输出相关信息:
// my-logging-plugin.js
export default function MyLoggingPlugin(eventBus) {eventBus.on('element.changed', function(event) {console.log('Element changed:', event.element);});
}MyLoggingPlugin.$inject = ['eventBus'];export default {__init__: ['myLoggingPlugin'],myLoggingPlugin: ['type', MyLoggingPlugin]
};
将该插件添加到 bpmn-js
实例中后,每当元素发生更改时,都会在控制台输出相应的信息。
📚 进一步阅读
- bpmn-js 官方文档
- didi GitHub 仓库(BPMN.io, bpmn.io Forum)
通过上述机制,bpmn-js
提供了强大的插件扩展能力,使开发者能够根据需求定制和扩展建模器的功能。