标准答案

  1. 主程序要提供 use(plugin, options) 这类注册方法。
  2. 插件通常暴露 install(app, options) 或 apply(context) 方法。
  3. 上下文只暴露必要能力,例如注册命令、注册钩子、读取配置、扩展实例方法。
  4. 要避免同一个插件重复安装,可以用 Set 做去重。
  5. 复杂插件系统还要处理生命周期顺序、依赖关系、错误隔离和权限边界。

题目解析

插件机制解决的是扩展能力和核心稳定性的矛盾。核心代码不能为每个业务场景无限加分支,但也不能让外部代码随便改内部状态。

好的插件接口应该小而稳定。插件拿到的是受控上下文,只能通过公开方法注册能力。这样核心内部重构时,只要插件 API 不变,插件就不需要跟着改。

执行顺序和重复安装也要考虑。插件如果注册路由、指令、命令或生命周期钩子,顺序不同可能影响结果;重复安装则可能导致重复监听和重复副作用。

代码示例

下面是一个最小插件系统:支持安装去重、暴露上下文和注册钩子。

JavaScript
function createApp() {
  const installedPlugins = new Set()
  const hooks = new Map()

  const app = {
    use(plugin, options) {
      if (installedPlugins.has(plugin)) {
        return app
      }

      installedPlugins.add(plugin)

      if (typeof plugin === 'function') {
        plugin(app, options)
      } else if (plugin && typeof plugin.install === 'function') {
        plugin.install(app, options)
      }

      return app
    },
    hook(name, callback) {
      const callbacks = hooks.get(name) || []
      callbacks.push(callback)
      hooks.set(name, callbacks)
    },
    emitHook(name, payload) {
      const callbacks = hooks.get(name) || []
      callbacks.forEach(callback => callback(payload))
    }
  }

  return app
}

常见误区

  • 插件直接修改内部私有状态,导致核心实现无法重构。
  • 没有安装去重,同一个插件重复注册事件或钩子。
  • 没有定义清楚插件生命周期和执行顺序,多个插件互相影响时难以排查。

作者信息