15

BPMN-JS中的依赖注入设计

 3 years ago
source link: https://sobird.me/design-of-dependency-injection-in-bpmn-js.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

为了扩展BPMN.JS的功能,我们通常在Modeler/Viewer实例化时通过传入 additionalModules 参数的方法来扩展/修改BPMN-JS的功能。

FvqumaY.png!web 一张图搞懂BPMN-JS设计

BPMN-JS通常通过类似下面的代码来自定义DI(依赖注入)模块:

export default class CustomRenderer extends BaseRenderer {
  constructor(eventBus, bpmnRenderer) {
    super(eventBus, HIGH_PRIORITY);

    this.bpmnRenderer = bpmnRenderer;
  }
  canRender(element) {
    return false;
  }
  drawShape(parentNode, element) {
    ...
  }
  getShapePath(shape) {
    ...
    return shape
  }
}
CustomRenderer.$inject = ['eventBus', 'bpmnRenderer'];

export default {
  __init__: ['CustomRenderer'],
  CustomRenderer: ['type', CustomRenderer]
}

上面代码实现了一个继承自 BaseRendererCustomRenderer 类, BaseRenderer 类是diagram-js包中实现的一个渲染基类(抽象类),里面定义了一些空的原型方法。通过上面的写法,我们就可以覆盖掉bpmn-js中 BaseRenderer 类的实现,从而实现了bpmn-js自定义渲染功能。

另外上面代码 CustomRenderer.$inject = ['eventBus', 'bpmnRenderer']; 而这实际上是bpmn.js依赖的diagram-js包所依赖的 didi 实现的依赖注入。

didi 是用JavaScript实现的一个依赖注入/控制反转容器。该库对外暴露了如下4个接口

  • annotate
  • parseAnnotations
  • Module
  • Injector

annotate

该方法用来将形如 ['a', 'b', 'c', function(a, b, c) {}] 通用的依赖注入写法,转换为 didi 特定的语法:

import { annotate } from "didi";

var fn = annotate(['a', 'b', 'c', function(a, b, c) {}]);
// 或
var fn = annotate('a', 'b', 'c', function(a, b, c) {});

// 输出结果为
var fn = function(a, b, c) {};
fn.$inject = ['a', 'b', 'c'];

parseAnnotations

该方法用来解析JavaScript函数的形参到一个数组,示例:

function Human(name, age) {
  this.name = name;
  this.age = age;
}

var res = parseAnnotations(Human);
// 结果 ['name', 'age']

Module

这是一个类,didi提供的自定义module接口,示例:

var { Module } = require('didi');

var carModule = new Module();
carModule.type('car', Car).factory('engine', createPetrolEngine).value('power', 1184);

// 或者通过对象字面量的方式来定义didi要注册的module
var carModule = {
  'car': ['type', Car],
  'engine': ['factory', createPetrolEngine],
  'power': ['value', 1184]
};

// 注册到Injector
var injector = new Injector([module]);

Injector

注入器,可以将上面定义的模块,通过一个数组参数实例化进该容器

const injector = new Injector([
  carModule
])

// get
injector.get('car').start();

// invoke
injector.invoke(['car', function(car) {
  car.start();
}]);

// 根据类的形参,在locals中查找依赖,并在类实例化时将形参依赖进行注入
injector.instantiate(function(a, b, c) {}, locals);
//
injector.createChild(modules, forceNewInstances);

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK