领域服务
领域服务(Domain Service)用于封装不自然地属于实体或值对象的领域逻辑。它是无状态的,处理跨多个聚合或实体的业务规则。
什么是领域服务
Section titled “什么是领域服务”领域服务具有以下特征:
- 无状态:不保存业务状态,只包含业务逻辑
- 操作多个对象:通常涉及多个实体或聚合
- 业务逻辑:包含重要的领域概念和规则
- 接口标记:实现
IDomainService接口
定义领域服务
Section titled “定义领域服务”using MiCake.DDD.Domain;
// 价格计算服务public class PricingService : IDomainService{ public Money CalculateTotalPrice(Order order, Customer customer) { var subtotal = order.GetSubtotal();
// 应用客户折扣 var discount = customer.GetDiscount(); var discountAmount = subtotal.Multiply(discount.AsDecimal());
// 计算税费 var taxRate = GetTaxRate(order.ShippingAddress); var taxAmount = subtotal.Subtract(discountAmount).Multiply(taxRate);
// 计算运费 var shippingCost = CalculateShipping(order, customer);
return subtotal .Subtract(discountAmount) .Add(taxAmount) .Add(shippingCost); }
private decimal GetTaxRate(Address address) { // 根据地址计算税率 return address.Country == "CN" ? 0.13m : 0.20m; }
private Money CalculateShipping(Order order, Customer customer) { if (customer.IsPremium) return Money.Zero("CNY");
return new Money(10.00m, "CNY"); }}
// 转账服务public class TransferService : IDomainService{ public void Transfer(BankAccount from, BankAccount to, Money amount) { if (from.Currency != amount.Currency || to.Currency != amount.Currency) throw new DomainException("Currency mismatch");
if (from.Balance < amount) throw new DomainException("Insufficient balance");
from.Withdraw(amount); to.Deposit(amount); }}领域服务 vs 应用服务
Section titled “领域服务 vs 应用服务”领域服务(Domain Service)
Section titled “领域服务(Domain Service)”// 领域服务:包含业务规则public class OrderPricingService : IDomainService{ // 计算订单价格的业务规则 public Money CalculateOrderTotal(Order order, List<Promotion> promotions) { var total = order.GetSubtotal();
foreach (var promotion in promotions.Where(p => p.AppliesTo(order))) { total = promotion.Apply(total); }
return total; }}应用服务(Application Service)
Section titled “应用服务(Application Service)”// 应用服务:协调领域对象和基础设施public class OrderApplicationService{ private readonly IRepository<Order, int> _orderRepository; private readonly IRepository<Customer, int> _customerRepository; private readonly OrderPricingService _pricingService; // 使用领域服务
public async Task<OrderDto> CreateOrder(CreateOrderCommand command) { // 1. 加载聚合 var customer = await _customerRepository.FindAsync(command.CustomerId);
// 2. 创建订单 var order = Order.Create(customer.Id); foreach (var item in command.Items) { order.AddItem(item.ProductId, item.Quantity, item.Price); }
// 3. 使用领域服务计算价格 var total = _pricingService.CalculateOrderTotal(order, customer.GetActivePromotions()); order.SetTotalAmount(total);
// 4. 持久化 await _orderRepository.AddAsync(order); await _orderRepository.SaveChangesAsync();
// 5. 返回 DTO return MapToDto(order); }}何时使用领域服务
Section titled “何时使用领域服务”✅ 应该使用领域服务
Section titled “✅ 应该使用领域服务”- 操作涉及多个聚合:
public class OrderFulfillmentService : IDomainService{ public bool CanFulfillOrder(Order order, List<Product> products) { // 检查多个产品的库存 foreach (var item in order.Items) { var product = products.First(p => p.Id == item.ProductId); if (product.Stock < item.Quantity) return false; } return true; }}- 复杂的业务计算:
public class ShippingCostCalculator : IDomainService{ public Money Calculate(Order order, Address from, Address to) { var distance = CalculateDistance(from, to); var weight = order.GetTotalWeight(); var dimensions = order.GetTotalDimensions();
// 复杂的运费计算逻辑 return CalculateShippingCost(distance, weight, dimensions); }}- 业务规则验证:
public class CreditCheckService : IDomainService{ public bool CheckCredit(Customer customer, Money amount) { var creditLimit = customer.GetCreditLimit(); var outstandingBalance = customer.GetOutstandingBalance();
return outstandingBalance.Add(amount).Amount <= creditLimit.Amount; }}❌ 不应该使用领域服务
Section titled “❌ 不应该使用领域服务”- 属于单个实体的逻辑:
// ❌ 不要:这应该是 Order 的方法public class OrderService : IDomainService{ public void AddItemToOrder(Order order, int productId, int quantity) { order.AddItem(productId, quantity); }}
// ✅ 正确:直接在 Order 中实现public class Order : AggregateRoot<int>{ public void AddItem(int productId, int quantity) { // 实现逻辑 }}- 纯技术性操作:
// ❌ 不要:这是基础设施服务,不是领域服务public class EmailSenderService : IDomainService{ public void SendEmail(string to, string subject, string body) { // 发送邮件 }}
// ✅ 正确:放在基础设施层public interface IEmailService{ Task SendEmailAsync(string to, string subject, string body);}领域服务通过依赖注入使用:
// 标记为作用域服务,自动注册public class PricingService : IDomainService, IScopedService{ private readonly ITaxRateProvider _taxRateProvider;
public PricingService(ITaxRateProvider taxRateProvider) { _taxRateProvider = taxRateProvider; }
public Money CalculateTotal(Order order) { var subtotal = order.GetSubtotal(); var taxRate = _taxRateProvider.GetRate(order.ShippingAddress); return subtotal.Multiply(1 + taxRate); }}
// 在应用服务中使用public class OrderApplicationService{ private readonly PricingService _pricingService;
public OrderApplicationService(PricingService pricingService) { _pricingService = pricingService; }
public async Task ProcessOrder(int orderId) { var order = await _orderRepository.FindAsync(orderId); var total = _pricingService.CalculateTotal(order); order.SetTotal(total); await _orderRepository.SaveChangesAsync(); }}1. 保持无状态
Section titled “1. 保持无状态”// ✅ 正确 - 无状态public class DiscountCalculator : IDomainService{ public Money Calculate(Order order, Customer customer) { // 不保存任何状态 return order.GetSubtotal().Multiply(customer.DiscountRate); }}
// ❌ 错误 - 有状态public class DiscountCalculator : IDomainService{ private Order _currentOrder; // 不要保存状态
public void SetOrder(Order order) { _currentOrder = order; }}2. 使用清晰的方法名
Section titled “2. 使用清晰的方法名”public class OrderService : IDomainService{ // ✅ 清晰的业务含义 public bool CanBeCancelled(Order order) { } public Money CalculateTotalWithTax(Order order, Address address) { } public bool MeetsMinimumOrderValue(Order order) { }}3. 依赖接口而非实现
Section titled “3. 依赖接口而非实现”public class PricingService : IDomainService{ private readonly ITaxRateProvider _taxRateProvider; // 接口 private readonly IShippingCalculator _shippingCalculator; // 接口
public PricingService( ITaxRateProvider taxRateProvider, IShippingCalculator shippingCalculator) { _taxRateProvider = taxRateProvider; _shippingCalculator = shippingCalculator; }}订单定价服务
Section titled “订单定价服务”public class OrderPricingService : IDomainService, IScopedService{ private readonly ITaxRateProvider _taxRateProvider; private readonly IShippingCalculator _shippingCalculator;
public OrderPricingService( ITaxRateProvider taxRateProvider, IShippingCalculator shippingCalculator) { _taxRateProvider = taxRateProvider; _shippingCalculator = shippingCalculator; }
public OrderPricing CalculatePricing(Order order, Customer customer) { // 1. 商品小计 var subtotal = CalculateSubtotal(order);
// 2. 应用折扣 var discount = CalculateDiscount(subtotal, customer);
// 3. 计算税费 var taxAmount = CalculateTax(subtotal - discount, order.ShippingAddress);
// 4. 计算运费 var shippingCost = _shippingCalculator.Calculate( order, customer.ShippingAddress );
return new OrderPricing { Subtotal = subtotal, Discount = discount, Tax = taxAmount, Shipping = shippingCost, Total = subtotal - discount + taxAmount + shippingCost }; }
private Money CalculateSubtotal(Order order) { return order.Items .Select(i => i.Price.Multiply(i.Quantity)) .Aggregate((a, b) => a.Add(b)); }
private Money CalculateDiscount(Money subtotal, Customer customer) { var discountRate = customer.GetDiscountRate(); return subtotal.Multiply(discountRate.AsDecimal()); }
private Money CalculateTax(Money amount, Address address) { var taxRate = _taxRateProvider.GetRate(address); return amount.Multiply(taxRate); }}领域服务用于封装不属于实体或值对象的业务逻辑:
- 实现
IDomainService接口 - 保持无状态
- 处理跨多个聚合的操作
- 包含复杂的业务规则
- 通过依赖注入使用
下一步: