NestJS下的CQRS实现 - Command、Event

之前的文章介绍了QueryBus, CommandBus的用法(这里的bus可以翻译为总线:查询总线、命令总线)。使用这些总线(设计模式)的目的在于实现Controller层与Business Logic层(示例中对应的是Commands/Queries下的Handler)的解耦。然而,通常在Business Logic之后还有一个Repository/Model层。Model(业务对象)除了属性(property)外,还有可能有行为。比如comments示例的业务对象,属性有id、comment,同时还带有行为: addLog等。 NestJS的EventBus正是为了实现业务对象的行为定义与实现的解耦,即Model对象发送一个Event指令给到EventBus,由EventBus找到对应的执行方法(EventHandler),从而实现解耦。
代码示例如下:
1:定义事件
comment-added.event.ts

export class CommentAddedEvent {
    constructor(
      public readonly id: string,
      public readonly comment: string,
    ) {}
  }

2:定义事件处理方法
comment-added.handler.ts

import { IEventHandler } from '@nestjs/cqrs';
import { EventsHandler } from '@nestjs/cqrs/dist/decorators/events-handler.decorator';
import { CommentAddedEvent } from '../impl/comment-added.event';

@EventsHandler(CommentAddedEvent)
export class CommentAddedHandler
  implements IEventHandler<CommentAddedEvent> {
  handle(event: CommentAddedEvent) {
    console.log('CommentAddedEvent...');
  }
}

3:定义对象模型
comment.model.ts, 注意:必须继承自AggregateRoot

import { AggregateRoot } from '@nestjs/cqrs';
import { CommentAddedEvent } from '../events/impl/comment-added.event';
export class Comment extends AggregateRoot {
  private readonly id: string;
  private readonly comment: string;

  constructor(_id: string, _comment?: string) {
    super();
    this.id = _id;
    this.comment = _comment;
    //console.log(`constructor model - id: ${this.id}`);
  }

  public DoSomething() {
    // logic
    this.apply(new CommentAddedEvent(this.id, this.comment));
  } 
}

4:修改CommandHandler,加入事件触发(Event)
注意此处的mergeObjectContext,这是将EventPublisher与Model关联起来的关键。

import { CommandHandler, ICommandHandler, EventPublisher } from '@nestjs/cqrs';
import { AddCommentCommand } from '../impl/add-comment.command';
import { Comment } from '../../models/comment.model';

@CommandHandler(AddCommentCommand)
export class AddCommentHandler implements ICommandHandler<AddCommentCommand> {
  constructor(
    private readonly publisher: EventPublisher,
  ) {}

  async execute(command: AddCommentCommand) {
    console.log(`AddCommentHandler, personId: ${command.personId}, comment: ${command.comment}`);

    const com = this.publisher.mergeObjectContext(new Comment(command.personId, command.comment));
    com.DoSomething();
    com.commit();
  }
}

最后,别忘了在XX.module.ts中,把EventHandler添加到Provider

import { Module } from '@nestjs/common';
import { CqrsModule } from '@nestjs/cqrs';
import { CommentsController } from './comments.controller';
import { QueryHandlers } from './queries/handlers';
import { CommandHandlers } from './commands/handlers';
import { EventHandlers } from './events/handlers';

@Module({
  imports: [CqrsModule],
  controllers: [CommentsController],
  providers: [
    ...QueryHandlers,
    ...CommandHandlers,
    ...EventHandlers,
  ],
})
export class CommentsModule {}

运行npm run start,用postman发出post请求,就可以看到结果。 具体实现请查看代码示例

posted @ 2021-09-07 14:51  老胡Andy  阅读(334)  评论(0编辑  收藏  举报