概念定义
最初的洞见是:应用逻辑与技术交付应能独立变化。六边形画出这条边界——内部是领域,边墙是端口,外部是适配器。
工作机制
驱动侧适配器(HTTP 处理器、队列消费者、CLI)经驱动端口调用核心操作;核心经自己定义的被驱动端口完成持久化与通知;适配器用具体技术实现被驱动端口。组装集中在一处——应用装配——核心因此零框架依赖。
使用场景
价值在业务规则而非数据搬运的服务、要无容器快速跑领域测试的团队、预期基础设施频繁更换的系统。纯数据铲运服务保持简单即可。
常见误区
它是依赖规则不是文件夹结构:核心代码绝不 import 适配器代码——目录只是形式,评审才是执行。把 ORM 实体注入领域,核心就被持久化框架绑死;按数据库镜像设计端口而非按用例设计,方向就反了。不加判断全面端口化,CRUD 端点只收获间接层。模式的退化形态是“端口后面的贫血模型加事务脚本”;领域与持久化两套模型之间的映射代码只在真正分歧时才值得付。
代码示例
export class FakeClock {
constructor(start = 0) {
if (!Number.isFinite(start)) throw new TypeError("start must be a finite number");
this.now = start;
this.timers = [];
this.seq = 0;
}
setTimeout(fn, delay) {
if (!Number.isFinite(delay) || delay <= 0) {
throw new RangeError("delay must be a positive number");
}
const entry = { id: ++this.seq, due: this.now + delay, fn };
this.timers.push(entry);
this.timers.sort((a, b) => a.due - b.due || a.id - b.id);
return entry.id;
}
clearTimeout(id) {
this.timers = this.timers.filter((t) => t.id !== id);
}
advance(ms) {
if (!Number.isFinite(ms) || ms < 0) throw new RangeError("ms must be >= 0");
const target = this.now + ms;
for (;;) {
const next = this.timers[0];
if (!next || next.due > target) break;
this.timers.shift();
this.now = next.due;
next.fn();
}
this.now = target;
}
get pending() {
return this.timers.length;
}
}