在 DDD 与微服务架构中,CQRS 和 GOF 命令模式 经常被混淆。很多开发者会把 CQRS 中的业务指令直接称作 "命令模式",但二者本质、职责、设计目标完全不同。
本文彻底厘清两者区别,并基于标准 GOF 命令模式实现:命令对象、调用者、接收者、命令队列、异步执行、撤销操作,结合 CQRS 读写分离思想,落地一套可直接上线的订单业务架构。
一、核心结论
1. 真正的命令模式(GOF 设计模式)
作用:把 "请求" 封装成对象,以便排队、记录、撤销、异步、事务。
GOF 命令模式是经典面向对象设计模式,核心思想是将请求封装为独立对象:
-
四大固定角色:抽象命令、具体命令、调用者 (Invoker)、接收者 (Receiver)
-
核心作用:请求者与执行者解耦,请求可被存储、排队、延迟、撤销、重做、日志、重放
-
扩展能力:天然支持命令队列、异步执行、失败重试、事务回滚
-
常见链路:
Invoker → Command → Receiver
- Command 抽象命令(接口)
- ConcreteCommand 具体命令(实现)
- Invoker 调用者(触发命令)
- Receiver 接收者(真正执行业务)
2. CQRS Command
**作用:把 "写请求" 和 "读请求" 分离。**它只是一个带参数的指令,不是设计模式。
CQRS 全称 Command Query Responsibility Segregation(命令查询责任分离),其 Command 只是业务读写拆分载体:
-
定位:数据传输对象 + 业务标识,区分「写操作」与「读操作」
-
核心作用:强制读写逻辑分离,写操作只修改数据、查询操作只读取数据
-
角色构成:无固定设计模式角色,仅作为入参 / 请求载体
-
扩展能力:仅承担参数传递、基础校验,不支持排队、撤销、异步重放
-
常见链路:
Controller → Command → Handler
3. 企业级可以参照GOF实战
CQRS + 命令模式 + 事件驱动
读写分离 + 请求对象化 + 业务解耦
|---------|---------------|------------------------|
| 对比项 | CQRS 业务命令 | GOF 标准命令模式 |
| 本质 | 读写分离的业务 DTO | 面向对象设计模式,请求对象化 |
| 固定角色 | 无 | 抽象命令、具体命令、调用者、接收者 |
| 核心目标 | 拆分读写逻辑,优化读写架构 | 解耦调用方与执行方,管控请求生命周期 |
| 队列 / 异步 | 不原生支持 | 原生支持命令队列、异步消费 |
| 撤销 / 重做 | 无法实现 | 原生支持 undo() 撤销操作 |
| 适用场景 | DDD、读写分离、业务分层 | 高并发、秒杀、任务队列、分布式事务、流程回滚 |
二、标准命令模式(真正 GOF 版)完整代码
1. 抽象命令(Command)
|-------------------------------------------------------------------------------------------------------------|
| java /** * 抽象命令接口(标准命令模式核心) */ public interface Command { void execute(); // 命令模式高级特性:撤销 void undo(); } |
2. 接收者(Receiver)------ 真正干活
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java /** * 接收者:真正执行订单业务 * 标准命令模式:业务全部在这里 */ @Component public class OrderReceiver { private final OrderRepositoryPort repository; private final OrderDomainService domainService; // 构造器注入 public OrderReceiver(OrderRepositoryPort repository, OrderDomainService domainService) { this.repository = repository; this.domainService = domainService; } // 创建订单(真正业务) public String createOrder(CreateOrderCommand command) { // 1. 防重校验(你要的:检查订单是否存在) if (repository.exists(command.getOrderId())) { throw new RuntimeException("订单已存在,禁止重复提交"); } // 2. 领域创建 Order order = domainService.createOrder( command.getUserId(), command.getSkuCode(), command.getCount(), command.getAmount() ); // 3. 落库 repository.save(order); return order.getOrderId(); } } |
3. 具体命令(ConcreteCommand)
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java /** * 具体命令:绑定接收者 + 执行业务 */ public class CreateOrderConcreteCommand implements Command { private final OrderReceiver receiver; private final CreateOrderCommand command; // 命令必须持有:接收者 + 请求参数 public CreateOrderConcreteCommand(OrderReceiver receiver, CreateOrderCommand command) { this.receiver = receiver; this.command = command; } // 标准命令模式:执行 @Override public void execute() { receiver.createOrder(command); } // 标准命令模式:撤销(undo) @Override public void undo() { System.out.println("【命令撤销】订单已取消:" + command.getOrderId()); } } |
4. 调用者(Invoker)------ 触发命令
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java /** * 调用者:触发命令,不关心谁执行、怎么执行 * 标准命令模式核心角色 */ @Component public class CommandInvoker { // 执行命令 public void invoke(Command command) { command.execute(); } // 撤销命令 public void undo(Command command) { command.undo(); } } |
三、CQRS + 命令模式整合(最终企业架构)
Controller(完全解耦)
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java @RestController @RequiredArgsConstructor public class OrderController { private final CommandInvoker invoker; private final OrderReceiver receiver; // ==================== CQRS 写命令 ==================== @PostMapping("/order/create") public String create(@RequestBody CreateOrderCommand req) { // 1. 构建标准命令对象 Command command = new CreateOrderConcreteCommand(receiver, req); // 2. 调用者执行 invoker.invoke(command); return "订单创建成功:" + req.getOrderId(); } // ==================== CQRS 查询 ==================== @GetMapping("/order/get") public OrderVO get(String orderId) { return getOrderQueryHandler.handle(new GetOrderQuery(orderId)); } } |
四、命令模式的真正威力
✅ 请求变成对象
可序列化、存储、队列、延迟、异步、日志、重放
✅ 调用者与执行者完全解耦
Controller 不关心业务逻辑
Receiver 不关心谁调用
✅ 天然支持撤销 / 重做(undo/redo)
订单取消、支付回滚、库存返还
✅ 支持命令队列、流量削峰
秒杀、排队下单
✅ 支持分布式事务
SAGA、TCC 模式底层全是命令模式
✅ 完美契合 CQRS
写 = 命令模式
读 = 自由查询
五、时序图:标准命令模式

六、CQRS 命令 vs 命令模式
1. CQRS Command(只是职责划分)
|-------------------------------------------|
| Plain Text Controller → Command → Handler |
只是读写分离,不是设计模式。
2. GOF 命令模式(真正设计模式)
|-----------------------------------------|
| Plain Text Invoker → Command → Receiver |
请求对象化、可控制、可扩展、可事务。
七、异步命令队列整体架构
本次实战架构:客户端 → 控制器 → 构建命令对象 → 命令队列(内存队列) → 异步线程消费 → 调用者执行命令 → 接收者执行业务
核心特性:
- 严格遵循 GOF 命令模式四大角色
- 实现命令队列,支持流量削峰
- 全链路异步执行,接口快速响应
- 支持命令撤销 undo()
- 内置订单重复校验、数据库持久化
- 与 CQRS 读写分离思想结合
八、异步命令队列完整代码实现
8.1 基础实体与端口
8.1.1 领域实体 Order
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data public class Order { private String orderId; private String userId; private String skuCode; private Integer count; private BigDecimal amount; private LocalDateTime createTime; // 领域业务规则 public void create() { if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) { throw new RuntimeException("订单金额必须大于0"); } if (count <= 0) { throw new RuntimeException("商品数量必须大于0"); } this.createTime = LocalDateTime.now(); } } |
8.1.2 仓储端口(六边形架构出站端口)
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import com.order.domain.entity.Order; public interface OrderRepositoryPort { // 保存订单 Order save(Order order); // 校验订单是否存在(防重复提交) boolean exists(String orderId); } |
8.1.3 领域服务
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import com.order.domain.entity.Order; import org.springframework.stereotype.Service; @Service public class OrderDomainService { public Order createOrder(String userId, String skuCode, Integer count, BigDecimal amount) { Order order = new Order(); order.setUserId(userId); order.setSkuCode(skuCode); order.setCount(count); order.setAmount(amount); order.create(); return order; } } |
8.1.4 持久化 PO & Mapper
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data public class OrderPO { private String orderId; private String userId; private String skuCode; private Integer count; private BigDecimal amount; private LocalDateTime createTime; } |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface OrderMapper { @Insert("INSERT INTO `order`(order_id, user_id, sku_code, count, amount, create_time) " + "VALUES(#{orderId}, #{userId}, #{skuCode}, #{count}, #{amount}, #{createTime})") int insert(OrderPO po); @Select("SELECT * FROM `order` WHERE order_id = #{orderId}") OrderPO selectByOrderId(String orderId); } |
8.1.5 仓储适配器
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import com.order.domain.entity.Order; import com.order.infra.mapper.OrderMapper; import com.order.infra.po.OrderPO; import com.order.port.repository.OrderRepositoryPort; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor public class OrderRepositoryAdapter implements OrderRepositoryPort { private final OrderMapper orderMapper; @Override public Order save(Order order) { OrderPO po = new OrderPO(); po.setOrderId(order.getOrderId()); po.setUserId(order.getUserId()); po.setSkuCode(order.getSkuCode()); po.setCount(order.getCount()); po.setAmount(order.getAmount()); po.setCreateTime(order.getCreateTime()); orderMapper.insert(po); return order; } @Override public boolean exists(String orderId) { return orderMapper.selectByOrderId(orderId) != null; } } |
8.2 GOF 命令模式核心角色
8.2.1 抽象命令接口(Command)
定义命令通用行为:执行、撤销、获取唯一标识
|-----------------------------------------------------------------------------------------------------------------|
| java public interface Command { // 执行命令 void execute(); // 撤销命令 void undo(); // 获取命令唯一标识 String getTraceId(); } |
8.2.2 接收者(Receiver)
真正执行业务逻辑,命令模式核心执行者,包含订单创建、撤销、防重校验
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import com.order.domain.entity.Order; import com.order.domain.service.OrderDomainService; import com.order.port.repository.OrderRepositoryPort; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component @RequiredArgsConstructor public class OrderReceiver { private final OrderRepositoryPort repository; private final OrderDomainService domainService; /** * 创建订单核心业务 */ @Transactional(rollbackFor = Exception.class) public String createOrder(CreateOrderCommand cmd) { // 防重复校验 if (repository.exists(cmd.getOrderId())) { throw new RuntimeException("订单已存在,禁止重复提交"); } // 领域逻辑 Order order = domainService.createOrder( cmd.getUserId(), cmd.getSkuCode(), cmd.getCount(), cmd.getAmount() ); order.setOrderId(cmd.getOrderId()); // 持久化落库 repository.save(order); return order.getOrderId(); } /** * 撤销/取消订单 */ public void cancelOrder(String orderId) { System.out.println("接收者 执行撤销操作,订单号:" + orderId); // 可扩展:删除订单、回滚库存、退款等逻辑 } } |
8.2.3 具体命令(ConcreteCommand)
实现抽象命令,持有接收者与业务参数,绑定执行逻辑
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import lombok.Data; import java.math.BigDecimal; @Data public class CreateOrderCommand implements Command { // 业务参数 private String orderId; private String userId; private String skuCode; private Integer count; private BigDecimal amount; // 持有接收者:命令依赖真正的业务执行者 private final OrderReceiver receiver; public CreateOrderCommand(OrderReceiver receiver) { this.receiver = receiver; } @Override public void execute() { receiver.createOrder(this); } @Override public void undo() { receiver.cancelOrder(this.orderId); } @Override public String getTraceId() { return this.orderId; } } |
8.2.4 调用者(Invoker)
负责触发命令执行,不关心具体业务逻辑,解耦调用方与执行方
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import org.springframework.stereotype.Component; @Component public class CommandInvoker { // 触发命令执行 public void execute(Command command) { command.execute(); } } |
8.3 命令队列 + 异步消费(核心扩展能力)
基于内存阻塞队列 + 线程池实现命令排队、异步执行,实现流量削峰
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import org.springframework.stereotype.Component; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ExecutorService; @Component public class CommandQueue { // 命令队列:阻塞队列,天然支持排队 private final BlockingQueue<Command> commandQueue = new LinkedBlockingQueue<>(); // 线程池:异步消费 private final ExecutorService executor = Executors.newFixedThreadPool(5); // 命令调用者 private final CommandInvoker invoker; public CommandQueue(CommandInvoker invoker) { this.invoker = invoker; // 启动异步消费线程 startAsyncConsumer(); } /** * 命令入队 */ public void offer(Command command) { commandQueue.offer(command); System.out.println("命令队列 命令入队,标识:" + command.getTraceId()); } /** * 异步消费逻辑 */ private void startAsyncConsumer() { executor.submit(() -> { while (true) { try { // 阻塞获取命令,无命令则等待 Command command = commandQueue.take(); // 调用者执行命令 invoker.execute(command); } catch (Exception e) { System.err.println("命令消费异常 " + e.getMessage()); } } }); } } |
8.4 控制器(对外接口 + CQRS 读写分离)

接口接收请求,构建命令并入队,接口立即返回,全程异步处理
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| java import com.order.command.CreateOrderCommand; import com.order.queue.CommandQueue; import com.order.receiver.OrderReceiver; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/order") @RequiredArgsConstructor public class OrderController { private final CommandQueue commandQueue; private final OrderReceiver receiver; /** * CQRS 写接口:创建订单(命令模式+队列异步) */ @PostMapping("/create") public String createOrder(@RequestBody CreateOrderCommand req) { // 1. 构建标准命令对象 CreateOrderCommand command = new CreateOrderCommand(receiver); command.setOrderId(req.getOrderId()); command.setUserId(req.getUserId()); command.setSkuCode(req.getSkuCode()); command.setCount(req.getCount()); command.setAmount(req.getAmount()); // 2. 命令入队,异步执行 commandQueue.offer(command); // 3. 接口立即响应,不阻塞前端 return "请求已接收,订单【" + req.getOrderId() + "】排队异步处理中"; } } |