一、啥是 CQRS 模式
在软件开发里,咱们经常会碰到业务逻辑很复杂的情况。要是把所有的业务逻辑都搅和在一起,代码就会变得乱糟糟,又难维护又难扩展。这时候,CQRS 模式就登场啦!
CQRS 就是命令查询职责分离(Command Query Responsibility Segregation)的缩写。简单来说,它把系统的操作分成了两类:命令(Command)和查询(Query)。命令是用来改变系统状态的,像创建、更新、删除这些操作;查询呢,就是用来获取系统数据的,不改变系统状态。这么一分离,代码结构就清晰多啦。
比如说,咱们有一个博客系统。当用户发表一篇新博客时,这就是一个命令操作,会改变系统的状态(数据库里多了一篇博客);而当用户查看博客列表时,这就是一个查询操作,只是从数据库里读取数据,不会改变系统状态。
二、MediatR 是个啥
MediatR 是一个轻量级的中介者模式实现库,在 .NET Core 里用得挺多。它能帮咱们实现消息的发布和处理,让不同的组件之间解耦。在 CQRS 模式里,MediatR 可以用来处理命令和查询消息。
举个例子,就好比一个公司里有很多部门,每个部门都有自己的职责。当有一个任务来了,不需要直接和具体的部门沟通,而是把任务交给一个中介(就像 MediatR),由中介把任务分配给合适的部门去处理。这样各个部门之间就不用互相依赖,代码也更好维护。
三、在 .NET Core 里结合 MediatR 实现 CQRS 模式
1. 创建项目
首先,咱们得创建一个 .NET Core 项目。打开命令行工具,输入下面的命令:
// C# 技术栈
dotnet new console -n CQRSExample
cd CQRSExample
这就创建了一个名为 CQRSExample 的控制台项目。
2. 安装 MediatR 包
在项目里安装 MediatR 和 MediatR.Extensions.Microsoft.DependencyInjection 包,命令如下:
// C# 技术栈
dotnet add package MediatR
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
3. 定义命令和查询
咱们来定义一个简单的命令和查询。假设咱们有一个用户管理系统,要实现创建用户和查询用户列表的功能。
先定义创建用户的命令:
// C# 技术栈
using MediatR;
// 定义创建用户的命令类
public class CreateUserCommand : IRequest<int>
{
public string Name { get; set; }
public string Email { get; set; }
public CreateUserCommand(string name, string email)
{
Name = name;
Email = email;
}
}
这里的 IRequest<int> 表示这个命令会返回一个整数,通常可以用来表示操作的结果(比如用户的 ID)。
再定义查询用户列表的查询:
// C# 技术栈
using MediatR;
using System.Collections.Generic;
// 定义查询用户列表的查询类
public class GetUsersQuery : IRequest<List<string>>
{
}
这里的 IRequest<List<string>> 表示这个查询会返回一个字符串列表,就是用户的名称列表。
4. 实现命令和查询的处理程序
接下来,要实现命令和查询的处理程序。
先实现创建用户命令的处理程序:
// C# 技术栈
using MediatR;
using System.Threading;
using System.Threading.Tasks;
// 创建用户命令的处理程序
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, int>
{
public async Task<int> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
// 这里可以实现具体的创建用户逻辑,比如插入数据库
// 为了简单,我们直接返回一个随机的用户 ID
return new Random().Next(1, 100);
}
}
再实现查询用户列表的处理程序:
// C# 技术栈
using MediatR;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
// 查询用户列表的处理程序
public class GetUsersQueryHandler : IRequestHandler<GetUsersQuery, List<string>>
{
public async Task<List<string>> Handle(GetUsersQuery request, CancellationToken cancellationToken)
{
// 这里可以实现具体的查询用户列表逻辑,比如从数据库读取
// 为了简单,我们直接返回一个固定的用户列表
return new List<string> { "User1", "User2", "User3" };
}
}
5. 配置 MediatR
在 Program.cs 里配置 MediatR:
// C# 技术栈
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var serviceCollection = new ServiceCollection();
// 注册 MediatR
serviceCollection.AddMediatR(typeof(Program));
var serviceProvider = serviceCollection.BuildServiceProvider();
var mediator = serviceProvider.GetService<IMediator>();
// 发送创建用户命令
var createUserCommand = new CreateUserCommand("John Doe", "johndoe@example.com");
var userId = await mediator.Send(createUserCommand);
Console.WriteLine($"User created with ID: {userId}");
// 发送查询用户列表查询
var getUsersQuery = new GetUsersQuery();
var users = await mediator.Send(getUsersQuery);
Console.WriteLine("Users:");
foreach (var user in users)
{
Console.WriteLine(user);
}
}
}
四、应用场景
1. 大型复杂业务系统
在大型的业务系统里,业务逻辑非常复杂,不同的业务模块之间交互频繁。使用 CQRS 模式可以把不同的业务逻辑分离,让代码更清晰,更易于维护和扩展。比如电商系统,订单管理、库存管理、用户管理等模块都可以采用 CQRS 模式。
2. 高并发系统
在高并发的系统里,查询和命令的性能需求不一样。查询操作通常需要快速响应,而命令操作可能需要更多的事务处理。CQRS 模式可以分别优化查询和命令的性能,提高系统的整体性能。比如在线游戏系统,玩家的查询操作(如查看排行榜)和命令操作(如购买道具)可以分开处理。
五、技术优缺点
优点
- 代码清晰:把命令和查询分离,代码结构更清晰,每个模块的职责更明确,易于理解和维护。
- 可扩展性强:当业务需求变化时,可以很方便地添加新的命令和查询处理程序,而不会影响其他模块。
- 性能优化:可以分别对查询和命令进行性能优化,提高系统的整体性能。
缺点
- 复杂度增加:引入 CQRS 模式会增加系统的复杂度,需要更多的代码和设计工作。
- 数据一致性问题:由于命令和查询分离,可能会出现数据不一致的情况,需要额外的处理来保证数据的一致性。
六、注意事项
1. 数据一致性
在 CQRS 模式里,要特别注意数据一致性问题。可以采用一些策略,比如最终一致性,让数据在一定时间内达到一致。
2. 日志和监控
由于系统变得更复杂,需要加强日志和监控,及时发现和解决问题。
3. 性能测试
在开发过程中,要进行充分的性能测试,确保系统的性能满足需求。
七、文章总结
通过在 .NET Core 里结合 MediatR 实现 CQRS 模式,咱们可以把复杂的业务逻辑清晰地分离,让代码更易于维护和扩展。虽然 CQRS 模式有一些缺点和需要注意的地方,但在合适的应用场景下,它能带来很大的好处。希望大家通过这篇文章,对 CQRS 模式和 MediatR 有了更深入的理解,能在实际项目中灵活运用。
评论