插件化机制最重要的事是什么?没错就是插件底座,我们要开发计算器,我们只关心计算器整个底座,至于计算器有什么计算功能,交给外部,外部灵活拓展。顺着这个思路,那么计算器的各种计算方法就是插件,我们需要某个计算功能的时候只需要往插件系统中注册对应插件即可。
// 程序主体,定义程序核心逻辑是增加计算器运算能力
class Calculator {
plugins = [];
constructor(initial) {
this.num = initial;
}
use(plugin) {
this.plugins.push(plugin);
this[plugin.name] = plugin.calculate.bind(this);
}
//use 方法是 Calculator 类的一个实例方法。它用于安装插件,并将插件添加到
//plugins 数组中。同时,它还会将插件的方法绑定到 Calculator 实例上,使得可
//以通过链式调用的方式来使用这些插件。这个方法接受一个 plugin 参数,该参数是
//一个实现了 Plugin 接口的实例。方法首先将插件添加到 plugins 数组中,然后使用
// plugin.name 作为键,将 plugin.calculate 方法绑定到 Calculator 实例上。这样,
//你就可以通过 Calculator 实例直接调用插件的方法,例如 myCalculator.add(5)。
//请注意,plugin.name 必须是一个合法的 JavaScript 属性名,否则会导致错误。
result() {
return this.num;
}
}
// 插件声明
interface Plugin {
name: string;
calculate(num: number) => this;
}
// 插件实现
class AddPlugin implements Plugin {
name: 'add',
calculate(num) {
this.num = this.num + num;
return this;
}
}
class SubtractPlugin implements Plugin {
name: 'subtract',
calculate(num) {
this.num = this.num - num;
return this;
}
}
const myCalculator = new Calculator(5);
// 插件安装
myCalculator.use(new AddPlugin());
myCalculator.use(new SubtractPlugin());
myCalculator.add(5).subtract(2).result(); // 8
经过这个改造,未来如果要实现乘法,我们只需要新增一个插件实现即可,无需修改程序主体:
class MultiplicatiPlugin implements Plugin {
name: 'multiplicati',
calculate(num) {
this.num = this.num * num;
return this;
}
}
再比如我们要增加一个 help 来打印支持的计算也可以快速实现:
class Calculator {
...
help() {
return `support ${this.plugins.map(plugin => plugin.name).join(',')}`;
}
}
通过上面的例子,从插件的角度可以分成几个部分:
-
程序主体(Program),我们通常也称之为插件底座,即上例中的 Calculator;
-
插件接口声明(Plugin Interface),即上例中的 Plugin;
-
插件实现(Plugin Implementation),即 AddPlugin,SubtractPlugin,MultiplicatiPlugin;
插件化机制用途非常广泛:
-
表单校验,校验规则就可以是插件化的,rules: [{required: true}, {max: 20}, {min: 10}]
-
webpack、vue、pinia 这些框架,他的能力拓展都是通过插件化实现的