← 中文资源

简体中文版本

六边形架构

六边形架构把领域核心与外部世界用端口与适配器隔开:业务逻辑无需基础设施即可测试,基础设施可整体替换。

阅读英文原文

概念定义

最初的洞见是:应用逻辑与技术交付应能独立变化。六边形画出这条边界——内部是领域,边墙是端口,外部是适配器。

工作机制

驱动侧适配器(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;
  }
}