Skip to content

cd /Users/sunxin/IdeaProjects/skeeter/tour-mate-platform && cat << 'EOF'

✅ ===== 架构修复与说明完成 =====

【已删除的重复文件】 ❌ tour-mate-platform-app/.../ActivityEventListener.java ❌ tour-mate-platform-infrastructure/adapter/ActivityNotificationAdapter.java

【正确的文件结构】 ✅ Domain 层 ├─ shared/event/ │ ├─ DomainEvent.java ← 事件基类(业务概念) │ ├─ IDomainEventPublisher.java ← Output Port(发布器接口) │ └─ package-info.java ← 架构说明文档 NEW! └─ activity/ ├─ event/ │ ├─ ActivityCreatedEvent.java │ └─ MemberJoinedEvent.java └─ port/out/ └─ IActivityNotificationPort.java ← Output Port(通知接口)

✅ Infrastructure 层 └─ adapter/ ├─ event/ │ ├─ DomainEventPublisherAdapter.java ← 实现 IDomainEventPublisher(Spring Event) │ └─ listener/ │ └─ ActivityEventListener.java ← 监听领域事件并调用通知 └─ notification/ └─ ActivityNotificationAdapter.java ← 实现 IActivityNotificationPort(通知渠道)

【架构解答】

Q1: shared/event 在 Domain 层干什么? ──────────────────────────────────── A: 提供跨聚合根复用的事件基础设施

  • DomainEvent:定义"事件"这个业务概念(不是技术实现)
  • IDomainEventPublisher:Domain 层定义的契约(Output Port)

类比:shared 就像是"工具箱",存放多个聚合根都需要的基础组件

  • shared/event/ → 事件相关
  • shared/valobj/ → 通用值对象(BaseId、Money)

Q2: 为什么有 DomainEventPublisherAdapter? ──────────────────────────────────── A: 这是六边形架构的 Driven Adapter(被驱动适配器)

Domain 层说:"我要发布事件"(IDomainEventPublisher 接口) Infrastructure 层说:"好的,我用 Spring Event 帮你发"(DomainEventPublisherAdapter)

优势: ✅ Domain 层不依赖 Spring ✅ 未来可以切换为 MQ(RocketMQ、Kafka) ✅ 可以 Mock 接口进行单元测试

Q3: 为什么 EventListener 在 Infrastructure 层? ──────────────────────────────────── A: 因为它使用了 Spring 技术

  • @TransactionalEventListener → Spring 特性
  • @Async → Spring 特性
  • 依赖具体的通知服务 → 技术实现

EventListener 的职责:

  1. 监听 Spring Event(技术)
  2. 调用 IActivityNotificationPort(业务契约)

Q4: NotificationAdapter 的作用? ──────────────────────────────────── A: 也是 Driven Adapter,整合多种通知渠道

Domain 层说:"我要发送通知"(IActivityNotificationPort 接口) Infrastructure 层说:"好的,我用短信/推送/站内信帮你发"(ActivityNotificationAdapter)

Adapter 内部可以:

  • 整合短信服务(阿里云、腾讯云)
  • 整合推送服务(极光、个推)
  • 整合站内信(数据库)
  • 根据用户偏好选择通知方式

【完整调用链】 ────────────────────────────────────

  1. ActivityAggregate.publishActivity() → addDomainEvent(new ActivityCreatedEvent(...))

  2. ActivityApplicationService.publishActivity() → domainEventPublisher.publishAll(events) [调用 Output Port]

  3. DomainEventPublisherAdapter.publishAll() → applicationEventPublisher.publishEvent(event) [Spring Event]

  4. ActivityEventListener.onActivityCreated() → notificationPort.notifyActivityCreated(event) [调用 Output Port]

  5. ActivityNotificationAdapter.notifyActivityCreated() → smsService.send(...) [短信] → pushService.send(...) [推送] → inAppService.send(...) [站内信]

【DDD 核心思想】 ──────────────────────────────────── Domain 层:定义业务规则和契约(What) Infrastructure 层:提供技术实现(How)

这不是"乱",这是标准的依赖倒置原则(DIP)!

【扩展通知类型】 ──────────────────────────────────── 只需要在 ActivityNotificationAdapter 中添加代码:

@Component public class ActivityNotificationAdapter {

@Resource private SmsService smsService;           ← 短信
@Resource private PushService pushService;         ← 推送
@Resource private InAppService inAppService;       ← 站内信
@Resource private EmailService emailService;       ← 邮件 NEW!
@Resource private WechatService wechatService;     ← 微信 NEW!

public void notifyActivityCreated(ActivityCreatedEvent event) {
    // 发送短信
    smsService.send(...);
    
    // 发送推送
    pushService.send(...);
    
    // 发送邮件
    emailService.send(...);  ← 新增
    
    // 发送微信模板消息
    wechatService.sendTemplateMessage(...);  ← 新增
}

}

不需要修改 Domain 层任何代码!这就是 DDD 的威力!

EOF

Powered by VitePress