采用命令模式处理学生申请系统消息/事件的方案咨询
CQRS命令结构设计方案(学生申请系统场景)
1. 是否需要为每种事件类型创建对应命令?
必须要。CQRS中命令的核心是表达单一业务意图,你提到的applicationSubmitted、applicationUpdated、offerAccepted这些事件对应完全不同的业务操作:
applicationSubmitted是初始化学生申请流程,需要校验申请材料完整性、生成申请编号applicationUpdated是修改已提交的申请信息,需要校验修改权限、更新对应数据offerAccepted是确认学生接受录取,需要触发后续注册流程、更新申请状态
给每种事件单独创建命令类,符合单一职责原则,能让每个命令的职责清晰,后续维护、扩展时不会互相干扰。同时也能和CQRS的命令处理程序一一对应,每个命令有专属的ICommandHandler<TCommand>实现,代码结构更规整。
举个C#代码示例:
// 基础命令接口 public interface IApplicationCommand { } // 对应applicationSubmitted的命令 public class ApplicationSubmittedCommand : IApplicationCommand { public Guid StudentId { get; set; } public ApplicationFormData FormData { get; set; } } // 对应applicationUpdated的命令 public class ApplicationUpdatedCommand : IApplicationCommand { public Guid ApplicationId { get; set; } public UpdatedApplicationData UpdatedData { get; set; } public Guid OperatorId { get; set; } // 记录操作人,用于权限校验 }
2. 是否应使用命令工厂?
非常有必要。从队列中取出的消息是通用格式(比如JSON字符串),只包含EventType和Payload两个核心字段,你需要把这些通用消息转换成对应的强类型命令对象。
用命令工厂可以把类型判断、命令实例化的逻辑封装起来,避免在队列消费代码里写一堆if-else或switch语句,让消费逻辑更简洁,也方便后续新增事件类型时只修改工厂代码,符合开闭原则。
C#示例实现:
public interface IApplicationCommandFactory { IApplicationCommand CreateCommand(string eventType, string payload); } public class ApplicationCommandFactory : IApplicationCommandFactory { private readonly IJsonSerializer _jsonSerializer; public ApplicationCommandFactory(IJsonSerializer jsonSerializer) { _jsonSerializer = jsonSerializer; } public IApplicationCommand CreateCommand(string eventType, string payload) { return eventType switch { "applicationSubmitted" => _jsonSerializer.Deserialize<ApplicationSubmittedCommand>(payload), "applicationUpdated" => _jsonSerializer.Deserialize<ApplicationUpdatedCommand>(payload), "offerAccepted" => _jsonSerializer.Deserialize<OfferAcceptedCommand>(payload), _ => throw new UnsupportedEventTypeException($"事件类型{eventType}未被支持") }; } }
在队列消费逻辑里,只需要调用工厂方法即可:
public class ApplicationEventConsumer { private readonly IApplicationCommandFactory _commandFactory; private readonly ICommandDispatcher _commandDispatcher; public ApplicationEventConsumer(IApplicationCommandFactory commandFactory, ICommandDispatcher commandDispatcher) { _commandFactory = commandFactory; _commandDispatcher = commandDispatcher; } public async Task ConsumeMessageAsync(QueueMessage message) { var command = _commandFactory.CreateCommand(message.EventType, message.Payload); await _commandDispatcher.DispatchAsync(command); } }
内容的提问来源于stack exchange,提问作者Rich W
相关产品推荐
相关产品推荐

