基本概念
命令 (Commands)
命令,说白了就是一次能改变系统状态的操作。通常通过向后端发起REST调用来实现。每个命令跑完会返回一个结果,执行的时候还会考虑执行策略。每次执行都会返回一个Observable——命令执行完了,它会发出一个可选的成功结果,然后结束;如果执行过程中间出了岔子,那就抛出错误。
这里有个细节得拎清楚:订阅这个结果Observable并不会触发命令的执行,订阅本身是可选的,你完全可以不订阅。
定义命令的方式很简单——把CommandService.create工厂方法的调用结果存成类的属性就行。一个命令通常包含两部分:
- 调度命令的函数(通常是调用连接器的函数)
- 选项对象(通常用来指定执行策略)
举个直观的例子:
protected updateCommand: Command<{ details: User }> = this.command.create(
(payload) =>
this.userIdService.takeUserId(true).pipe(
switchMap((uid) =>
this.userProfileConnector.update(uid, payload.details)
),
{
strategy: CommandStrategy.Queue,
}
);
查询 (Queries)
查询和命令最大的区别在于:查询不会改变系统状态,它只是从系统里把数据捞出来,不搞破坏。通常查询也返回一个Observable,发出数据后结束,供订阅者消费。和命令一样,查询也可以配置执行策略。
执行策略
命令和查询的执行方式,可以通过执行策略来灵活控制。常见的就这么几种:
- Parallel(并行):所有命令或查询同时开跑,不管顺序。
- Queue(队列):按照调用的先后顺序排队执行,这是默认策略。
- CancelPrevious(取消上一个):如果前一个还没执行完,新的执行一启动,就把上一个取消掉。上一个的结果流会直接完成,不发出任何值。
- ErrorPrevious(上一个错误):如果前一个还在跑,新的执行开始了,那么上一个就会报错。上一个的结果流会抛出一个错误。
实际示例
光说概念容易晕,咱们拿一个实际场景来感受一下。假设我们在做一个用户管理系统,现在需要创建一个命令来更新用户详情。
第一步,定义更新命令:
protected updateCommand: Command<{ details: User }> = this.command.create(
(payload) =>
this.userIdService.takeUserId(true).pipe(
switchMap((uid) =>
this.userProfileConnector.update(uid, payload.details)
),
{
strategy: CommandStrategy.Queue,
}
);
在这个例子里,updateCommand接收用户详情,然后发往后端。执行策略选的是队列——多个更新请求按顺序逐个执行,保证数据不会乱。
再来个查询的例子。假设我们要获取某个用户的个人资料:
protected getUserProfileQuery: Query<{ userId: string }, UserProfile> = this.query.create(
(payload) => this.userProfileConnector.getProfile(payload.userId),
{
strategy: QueryStrategy.Parallel,
}
);
getUserProfileQuery这个查询,拿用户ID当输入,从后端把用户资料取回来。这里选的是并行策略——同时拿多个用户的资料也没问题,性能更好。
总结
Commands and Queries设计模式在Angular应用开发里是个核心概念,能帮你把系统状态和后端交互管得明明白白。命令搞定那些可能改变系统状态的操作,查询只负责取数据、不动原始状态。执行策略则给了你控制执行方式的灵活度:并行、队列、取消上一个、报错上一个——按需选择。
好好用这个模式,能让Angular应用的性能和可维护性都上一个台阶。系统状态一致性有保障,和后端的通信也更清晰。对于复杂应用来说,它就像一把趁手的工具,让代码的组织和管理变得更清爽。
