Cordis可调用服务进阶:Service.invoke与extend高级用法完整指南
【免费下载链接】cordisMeta-Framework of Spatiotemporal Composability项目地址: https://gitcode.com/GitHub_Trending/co/cordis
Cordis 是一个强调"时空可组合性"(Spatiotemporal Composability)的元框架(Meta-Framework),其核心价值在于用统一的可调用服务(Callable Service)模型,让插件之间通过ctx.xxx()这样的函数式调用完成组合。本文将深入讲解Service.invoke与Service.extend这两个高级特性,帮助新手快速掌握如何把普通服务改造成"既能当对象用、又能当函数调"的进阶形态。
一、什么是 Cordis 可调用服务(Functional Service)?
在 Cordis 中,服务(Service)通常是挂载在 Context 上的具名对象,例如ctx.logger、ctx.events。而可调用服务是一类特殊的服务:它除了具备普通服务的全部能力外,还能像函数一样被直接调用。
// 普通服务:访问属性 ctx.logger.info('hello') // 可调用服务:直接调用 ctx.foo() // 返回配置合并结果 ctx.foo.extend({}) // 生成一个派生的新服务这种设计让服务对外暴露"一个入口、多份行为",非常适合实现"配置工厂""请求代理""依赖查找"等场景。核心实现集中在 service.ts 中,其中Service.invoke与Service.extend两个静态符号正是开关。
二、Service.invoke 核心用法:让服务可被直接调用
要让一个服务变得"可调用",只需在类中实现[Service.invoke]()方法。框架检测到该方法存在后,会通过 utils.ts 中的createCallable将实例包装成函数对象。
class Foo extends Service { constructor(ctx: Context, public config: Config) { super(ctx, 'foo') } protected Service.invoke { // 这里定义"调用"时发生什么 return { ...this.config, ...init } } } await root.plugin(Foo, { a: 1 }) root.foo() // => { a: 1 } root.foo({ b: 2 }) // => { a: 1, b: 2 }关键点有三:
- 调用即执行:
ctx.foo(...)会触发[Service.invoke],返回值就是调用结果; - 上下文可追踪:调用时
this.ctx仍是正确的 Context,配合 Cordis 的 Traceable 机制,在子上下文(如inject回调)中调用也能拿到正确的隔离环境; - 实例检测不失效:包装后的服务依然满足
instanceof Foo,因为其原型链被joinPrototype拼接,兼容性极佳。
三、Service.extend 高级技巧:派生可调用服务
Service.extend用于基于现有服务创建"扩展副本",它会在不污染原服务的前提下,给新对象附加额外属性。
class Foo extends Service { extend(config?: Config) { return thisService.extend } } const foo2 = root.foo.extend({ c: 3 }) foo2() // => { a: 1, c: 3 } root.foo() // => { a: 1 } 原服务不受影响为什么有用?扩展副本继承了原始服务的方法与原型,却拥有独立的状态。这就像给同一个"函数"复制了一份可定制的新函数,特别适合:
- 为不同租户/频道准备差异化配置;
- 在库内部派生带默认参数的调用入口;
- 组合多个服务的可调用能力。
四、组合使用:可调用服务 + 配置拦截
可调用服务与ctx.intercept()结合,能实现优雅的"分层配置覆盖"。参考 invoke.spec.ts 中的测试,可以这样理解执行顺序:
const ctx1 = root.intercept('foo', { b: 2 }) ctx1.foo() // => { a: 1, b: 2 } 基础配置 + 拦截配置- 基础配置:插件注册时的
config; - 拦截配置:
ctx.intercept(name, config)在调用链上逐层叠加; - 调用参数:
invoke传入的参数优先级最高。
这样一条调用链,天然实现了"全局默认 → 分层覆盖 → 单次定制"的三级配置合并,代码量却极小。
五、常见陷阱与最佳实践
- 记得返回
this[Service.extend]的结果:实现extend()公开方法时,务必返回Service.extend的产物,而不是this本身,否则丢失原型能力; invoke中避免直接修改外部状态:可调用服务常被多次调用,应保持纯函数式风格,把结果返回给调用方;- 善用测试用例学习:仓库中的 invoke.spec.ts 与 service.spec.ts 覆盖了"函数式服务""影子上下文""追踪调用者"等完整场景,是理解进阶用法的绝佳教材。
结语
Service.invoke与Service.extend是 Cordis 可调用服务体系的"双引擎":前者让服务拥有函数式入口,后者让服务具备可派生性。掌握这两个 API,你就能写出既简洁又富有弹性的插件架构。如果想深入源码,重点阅读 service.ts 与 utils.ts 中的createCallable、joinPrototype,配合测试文件食用效果更佳。🚀
【免费下载链接】cordisMeta-Framework of Spatiotemporal Composability项目地址: https://gitcode.com/GitHub_Trending/co/cordis
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考