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请求,就可以看到结果。 具体实现请查看代码示例