














https://jdaniel1987.github.io/CleanArchitecture

这篇博文的核心在于通过分层来解耦,而 Program.cs 正是实现这种解耦的“总装车间”。将两者结合,能完美地展示从理论到实践的闭环。
https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles

https://github.com/fanqingsong/CleanArchitecture_extension
https://github.com/fanqingsong/CleanArchitecture/tree/main/MinimalClean
整洁架构(Clean Architecture)由罗伯特·C·马丁(Robert C. Martin,又称 Uncle Bob)推广,它强调通过清晰的分层和边界来分离软件系统,确保业务逻辑独立于 UI、数据库或框架等外部细节。这种分离使得系统更易于维护、测试和扩展。
本文将深入探讨整洁架构的核心概念,并展示如何通过“构造与运行分离”这一关键实践,在 .NET 项目中落地这些原则。
整洁架构的魅力在于其清晰的规则,这些规则共同守护着核心业务逻辑的纯净。
1. 关注点分离 (Separation of Concerns)
整洁架构通过将代码组织成不同的层来实现清晰的职责划分。依赖关系应该单向流动:从外层(基础设施、UI)指向内层(业务逻辑)。
2. 依赖倒置原则 (Dependency Inversion Principle, DIP)
这是实现解耦的基石。它指出:高层模块不应该依赖低层模块,二者都应该依赖其抽象。
在整洁架构中,这意味着我们的业务逻辑(高层模块)只依赖接口,而具体的数据库或外部服务实现(低层模块)也去实现这些接口。
示例:依赖倒置
// 高层模块 - 业务逻辑
public class OrderService
{
private readonly IOrderRepository _orderRepository;
// 依赖通过构造函数注入,只依赖抽象 IOrderRepository
public OrderService(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
public void PlaceOrder(Order order)
{
// 业务逻辑
_orderRepository.Save(order);
}
}
// 低层模块 - 具体实现
public class SqlOrderRepository : IOrderRepository
{
public void Save(Order order)
{
// 将订单保存到 SQL 数据库
}
}
3. 实体 (Entities)
实体是封装了企业级业务规则的核心业务对象。它们应该完全独立于外部服务、数据库和 UI。
public class Order
{
public Guid Id { get; set; }
public DateTime OrderDate { get; set; }
public Customer Customer { get; set; }
public List<OrderItem> Items { get; set; }
// 业务逻辑:计算订单总额
public decimal TotalAmount => Items.Sum(item => item.Price * item.Quantity);
}
4. 用例 (Use Cases / Application Layer)
用例层包含特定于应用程序的业务逻辑。它协调实体和外部服务(如仓储、通知)之间的交互,但同样是通过抽象接口进行的。
public class PlaceOrderUseCase
{
private readonly IOrderRepository _orderRepository;
private readonly IPaymentService _paymentService;
public PlaceOrderUseCase(IOrderRepository orderRepository, IPaymentService paymentService)
{
_orderRepository = orderRepository;
_paymentService = paymentService;
}
public void Execute(Order order)
{
// 协调业务逻辑
_paymentService.ProcessPayment(order);
_orderRepository.Save(order);
}
}
5. 接口适配器 (Interface Adapters)
这一层负责数据格式的转换。例如,将数据库的数据模型转换为用例层需要的实体,或将实体转换为 UI 层需要的 DTO。
public class OrderDto
{
public Guid Id { get; set; }
public DateTime OrderDate { get; set; }
public string CustomerName { get; set; }
}
// 在某个 Mapper 类中
public OrderDto ToOrderDto(Order order)
{
return new OrderDto()
{
Id = order.Id,
OrderDate = order.OrderDate,
CustomerName = order.Customer.Name
};
}
6. 框架与外部工具 (Frameworks and External Tools)
最外层由数据库、Web 框架等具体技术实现组成。它们不包含业务逻辑,只负责实现内层定义的接口。
整洁架构通常被描绘成同心圆,依赖关系由外向内。
一个常见的误区是混淆依赖方向和数据流向。
理解了分层和依赖倒置,我们如何实现它?答案就是“构造与运行分离”。这个思想在 .NET 中通过依赖注入(DI)容器完美实现。
OrderService)不关心依赖是如何创建的,只通过构造函数接收它们。在 ASP.NET Core 中,Program.cs 文件就是我们的“组合根”。
完整的 Program.cs 示例
using Infrastructure; // 基础设施层
using Application; // 应用层
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// ==============================================================================
// 1. 构造阶段 (Construction Phase)
// ==============================================================================
// 这是“组合根”,所有依赖关系都在这里集中配置。
// 业务逻辑层(Application 和 Domain)完全不知道这里的存在。
// --- 1.1 添加框架服务 ---
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// --- 1.2 添加基础设施层服务 ---
// 配置数据库上下文
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// 注册具体实现:当需要 IOrderRepository 时,提供 SqlOrderRepository 实例
builder.Services.AddScoped<IOrderRepository, SqlOrderRepository>();
builder.Services.AddScoped<IEmailSender, SmtpEmailSender>();
// --- 1.3 添加应用层服务 ---
// 注册用例或 MediatR
builder.Services.AddScoped<PlaceOrderUseCase>();
var app = builder.Build();
// ==============================================================================
// 2. 运行阶段 (Runtime Phase)
// ==============================================================================
// 配置 HTTP 请求处理管道。应用程序开始监听并响应请求。
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
这段代码清晰地展示了分离:
builder 部分,我们告诉 DI 容器如何组装对象。例如,AddScoped<IOrderRepository, SqlOrderRepository>() 这条规则,就是连接抽象与实现的桥梁。app.Run() 之后,当请求到达 OrderController 时,框架会自动根据我们设定的规则,创建 PlaceOrderUseCase,并自动注入它所需的 IOrderRepository 实现。业务代码本身完全干净,不涉及任何 new 操作。优势
挑战
整洁架构提供了一套强大的原则来构建可维护、可测试和灵活的系统。而“构造与运行分离”是实现这些原则的关键实践。通过在 Program.cs 中集中管理对象的创建,我们可以确保核心业务逻辑的纯净和独立,从而构建出真正健壮的软件。
出处:http://www.cnblogs.com/lightsong/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。