DecoratR优雅的装饰器模式实现库
2025-08-17 22:54:34.Net生态有一个大名鼎鼎中介者模式实现库MediatR,今天介绍一个优雅的装饰器模式实现库DecoratR。
作为软件工程师,我们不断面临在应用程序中实现横切关注点的挑战,例如日志记录、缓存、验证、重试逻辑和安全性。传统方法通常会导致:
- 重复的样板代码散布在你的服务中。
- 业务逻辑与基础设施关注点之间紧密耦合。
- 由于职责混合而导致测试困难。
- 当需求变更时,可维护性差。
考虑这个典型的服务方法:
public async Task<Order> GetOrderAsync(int orderId)
{
_logger.LogInformation("Getting order {OrderId}", orderId); // 正在获取订单 {OrderId}
// 先检查缓存
var cacheKey = $"order_{orderId}";
if (_cache.TryGetValue(cacheKey, out Order cachedOrder))
{
_logger.LogInformation("Order {OrderId} found in cache", orderId); // 订单 {OrderId} 在缓存中找到
return cachedOrder;
}
try
{
// 验证输入
if (orderId <= 0)
thrownew ArgumentException("Invalid order ID"); // 无效的订单 ID
// 业务逻辑埋没在基础设施代码中
var order = await _repository.GetOrderAsync(orderId);
// 缓存结果
_cache.Set(cacheKey, order, TimeSpan.FromMinutes(5));
_logger.LogInformation("Order {OrderId} retrieved successfully", orderId); // 订单 {OrderId} 成功获取
return order;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get order {OrderId}", orderId); // 获取订单 {OrderId} 失败
throw;
}
}
此方法违反了单一职责原则(Single Responsibility Principle),并成为维护的噩梦。如果我们需要添加指标、安全检查或速率限制怎么办?该方法会变得越来越复杂。
一、DecoratR:简洁、可组合的服务装饰
DecoratR 是一个现代的 .NET 库,它通过流畅、直观的 API 将装饰器模式(Decorator pattern)引入到 Microsoft 的依赖注入(DI)容器中。它允许你以简洁、可组合的方式用横切关注点包装你的服务。
核心特性
- 流式 API (Fluent API) — 直观且可读的装饰器链配置。
- 常规与键控服务 (Regular & Keyed Services) — 全面支持 .NET 8+ 的键控服务。
- 自定义工厂 (Custom Factories) — 处理复杂的依赖注入场景。
- 泛型装饰器 (Generic Decorators) — 支持泛型装饰器。
- 条件装饰 (Conditional Decoration) — 根据条件应用装饰器。
- 生命周期管理 (Lifetime Management) — 控制服务的生命周期(Singleton, Scoped, Transient)。
快速开始
通过Nuget安装依赖库
dotnet add package DecoratR
将复杂的服务方法转化为职责分离的简洁形式
public class LoggingDecorator : IOrderService { private readonly IOrderService _inner; public LoggingDecorator(IOrderService inner) => _inner = inner; public string GetOrder(string orderId) { Console.WriteLine("LoggingDecorator: 开始请求 (Starting request)"); var result = _inner.GetOrder(orderId); Console.WriteLine("LoggingDecorator: 请求完成 (Request completed)"); return $"Logged({result})"; } } public class CacheDecorator : IOrderService { private readonly IOrderService _inner; public CacheDecorator(IOrderService inner) => _inner = inner; public string GetOrder(string orderId) { Console.WriteLine("CacheDecorator: 正在检查缓存 (Checking cache)"); var result = _inner.GetOrder(orderId); Console.WriteLine("CacheDecorator: 正在存入缓存 (Storing in cache)"); return $"Cached({result})"; } } public class OrderService : IOrderService { private readonly IOrderRepository _repository; public OrderService(IOrderRepository repository) => _repository = repository; public string GetOrder(string orderId) { Console.WriteLine("OrderService: 正在从数据库获取 (Fetching from database)"); return $"Order: {orderId}"; } }
注入配置
services.Decorate<IOrderService>() .With<SecurityDecorator>() // 最外层 - 最先执行 .Then<LoggingDecorator>() // 中间层 .Then<CacheDecorator>() // 内层 .Then<OrderService>() // 基础实现 - 最内层 .Apply(); //执行流程从外向内移动:安全 (Security) → 日志 (Logging) → 缓存 (Cache) → 业务逻辑 (Business Logic)
使用
// 使用 var provider = services.BuildServiceProvider(); var orderService = provider.GetService<IOrderService>(); var result = orderService.GetOrder("123"); Console.WriteLine(result); // 输出: // LoggingDecorator: 开始请求 (Starting request) // CacheDecorator: 正在检查缓存 (Checking cache) // OrderService: 正在从数据库获取 (Fetching from database) // CacheDecorator: 正在存入缓存 (Storing in cache) // LoggingDecorator: 请求完成 (Request completed) // Logged(Cached(Order: 123))
二、高级特性
- 条件装饰 (Conditional Decoration) — 基于条件应用装饰器:
var isDevelopment = Environment.GetEnvironmentVariable("ENVIRONMENT") == "Development";
var enableCaching = configuration.GetValue<bool>("Features:Caching");
services.Decorate<IOrderService>()
.With<LoggingDecorator>()
.ThenIf<RetryDecorator>(isDevelopment) // 仅在开发环境
.ThenIf<CacheDecorator>(enableCaching) // 基于配置
.Then<OrderService>()
.Apply();
- 键控服务 (.NET 8+) — 为相同服务类型创建不同的装饰器链:
// 为不同上下文使用不同配置
services.Decorate<IOrderService>("internal") // "内部"键
.With<LoggingDecorator>()
.Then<OrderService>()
.Apply();
services.Decorate<IOrderService>("external") // "外部"键
.With<SecurityDecorator>()
.Then<RateLimitingDecorator>()
.Then<LoggingDecorator>()
.Then<OrderService>()
.Apply();
// 使用
var internalService = provider.GetRequiredKeyedService<IOrderService>("internal");
var externalService = provider.GetRequiredKeyedService<IOrderService>("external");
- 自定义工厂方法 (Custom Factory Methods) — 对于需要自定义依赖注入的复杂场景:
services.Decorate<IOrderService>()
.With((serviceProvider, inner) =>
new MetricsDecorator(
inner,
serviceProvider.GetRequiredService<IMetrics>(),
serviceProvider.GetRequiredService<IConfiguration>()
.GetValue<string>("MetricsPrefix")))
.Then<OrderService>()
.Apply();
- 泛型装饰器 (Generic Decorators):
public class GenericCacheDecorator<T> : IService<T>
{
privatereadonly IService<T> _inner;
public GenericCacheDecorator(IService<T> inner) => _inner = inner;
public T Get(string key) => /* 缓存逻辑 (caching logic) */ _inner.Get(key);
}
services.Decorate<IService<User>>()
.With<GenericCacheDecorator<User>>()
.Then<UserService>()
.Apply();
三、实际应用场景
电子商务平台 (E-commerce Platform)
public class ECommerceConfiguration
{
public void ConfigureServices(IServiceCollection services, IConfiguration config)
{
var enableMetrics = config.GetValue<bool>("Features:Metrics");
var enableRetry = config.GetValue<bool>("Features:Retry");
// 订单处理流水线
services.Decorate<IOrderService>()
.With<SecurityDecorator>() // 首先认证
.Then<ValidationDecorator>() // 验证输入
.ThenIf<MetricsDecorator>(enableMetrics) // 可选的指标
.ThenIf<RetryDecorator>(enableRetry) // 可选的重试逻辑
.Then<CacheDecorator>() // 缓存近端数据
.Then<OrderService>() // 业务逻辑
.AsScoped() // 设置为作用域生命周期
.Apply();
// 支付处理 - 不同的需求
services.Decorate<IPaymentService>()
.With<AuditDecorator>() // 审计所有支付
.Then<EncryptionDecorator>() // 加密敏感数据
.Then<RateLimitingDecorator>() // 防止滥用
.Then<PaymentService>()
.Apply();
}
}
多租户 SaaS 应用程序 (Multi-tenant SaaS Application)
// 不同租户层级的不同功能集
services.Decorate<IDataService>("basic-tier") // "基础版"键
.With<LoggingDecorator>()
.Then<DataService>()
.Apply();
services.Decorate<IDataService>("premium-tier") // "高级版"键
.With<LoggingDecorator>()
.Then<CacheDecorator>()
.Then<MetricsDecorator>()
.Then<DataService>()
.Apply();
services.Decorate<IDataService>("enterprise-tier") // "企业版"键
.With<SecurityDecorator>()
.Then<AuditDecorator>()
.Then<LoggingDecorator>()
.Then<CacheDecorator>()
.Then<MetricsDecorator>()
.Then<DataService>()
.Apply();
四、最佳实践
装饰器顺序至关重要:
services.Decorate<IService>() .With<SecurityDecorator>() // 认证/授权最先 .Then<RateLimitingDecorator>() // 速率限制在安全之后 .Then<LoggingDecorator>() // 在安全检查之后记录日志 .Then<MetricsDecorator>() // 收集指标 .Then<CacheDecorator>() // 缓存最接近数据 .Then<BusinessService>() // 纯粹的业务逻辑 .Apply();
保持装饰器职责单一
// 好 - 单一关注点 public class CacheDecorator : IOrderService { // 只处理缓存逻辑 } // 坏 - 多个关注点 public class CacheAndLogDecorator : IOrderService { // 同时处理缓存和日志记录 - 违反 SRP }
使装饰器可测试
[Test] public void LoggingDecorator_Should_LogExecution() // LoggingDecorator 应记录执行 { // 准备 (Arrange) var mockInner = new Mock<IOrderService>(); var mockLogger = new Mock<ILogger>(); var decorator = new LoggingDecorator(mockInner.Object, mockLogger.Object); // 执行 (Act) decorator.GetOrder("123"); // 断言 (Assert) mockLogger.Verify(x => x.LogInformation(It.IsAny<string>()), Times.AtLeastOnce); // 验证至少记录一次信息 mockInner.Verify(x => x.GetOrder("123"), Times.Once); // 验证内部服务方法被调用一次 }
明智地使用条件装饰
// 好 - 条件在启动时仅评估一次 services.Decorate<IService>() .WithIf<ExpensiveDecorator>(enableExpensiveFeature) // 启用昂贵特性时才应用 .Then<BaseService>() .Apply(); // 坏 - 条件在每次调用时评估 public class ConditionalDecorator : IService { public Result Execute() { if (someRuntimeCondition) // 每次调用都评估! { // 昂贵的操作 } return _inner.Execute(); } }
五、性能考量
DecoratR 专为性能而设计:
- 对于未应用的条件装饰器,运行时开销为零。
- 最小化内存分配 — 装饰器在 DI 容器设置期间仅创建一次。
- 方法执行期间不使用反射(Reflection)。
六、开始迁移
之前:
// 手动注册 - 易错且冗长
services.AddScoped<IOrderService>(provider =>
{
var baseService = new OrderService(provider.GetService<IRepository>());
var cached = new CacheDecorator(baseService, provider.GetService<ICache>());
var logged = new LoggingDecorator(cached, provider.GetService<ILogger>());
return logged;
});
之后:
// 简洁、流式的 API
services.Decorate<IOrderService>()
.With<LoggingDecorator>()
.Then<CacheDecorator>()
.Then<OrderService>()
.Apply();
平台支持
DecoratR 支持多个 .NET 版本:
- .NET 6.0 — 核心装饰功能
- .NET 7.0 — 核心装饰功能
- .NET 8.0 — 完整功能集,包括键控服务
- .NET 9.0 — 最新特性和优化
键控服务仅在 .NET 8.0 及更高版本中可用,但所有其他功能在所有支持的版本中均可使用。