VCD文件解析与Verilog Testbench自动生成实战指南
2026/8/6 6:24:02
Presentation Layer (UI) ↓Application Layer (应用服务) ↓Domain Layer (领域模型) ← 本节课重点 ↓Infrastructure Layer (基础设施,如EF Core、Repository)领域层是“心脏”,其他层都依赖于它,而不是反过来。—### 二、从基础开始:定义实体和值对象在领域模型中,我们通常分为两类对象:-实体(Entity):具有唯一标识(ID)的对象,例如Order。-值对象(Value Object):没有唯一标识,由属性值定义的对象,例如Money或Address。#### 代码示例1:定义实体和值对象下面是一个简单的订单领域模型,包含实体和值对象。csharp// 值对象:表示金额public class Money{ public decimal Amount { get; private set; } public string Currency { get; private set; } public Money(decimal amount, string currency) { if (amount < 0) throw new ArgumentException("金额不能为负数"); Amount = amount; Currency = currency; } // 值对象之间的相等比较基于属性值 public override bool Equals(object obj) => obj is Money other && Amount == other.Amount && Currency == other.Currency; public override int GetHashCode() => HashCode.Combine(Amount, Currency);}// 实体:订单public class Order{ public int Id { get; private set; } // 实体唯一标识 public Money TotalAmount { get; private set; } public DateTime OrderDate { get; private set; } public string Status { get; private set; } public Order(int id, Money totalAmount, DateTime orderDate) { Id = id; TotalAmount = totalAmount ?? throw new ArgumentNullException(nameof(totalAmount)); OrderDate = orderDate; Status = "待支付"; } // 业务操作:支付订单 public void Pay() { if (Status != "待支付") throw new InvalidOperationException("订单状态不允许支付"); Status = "已支付"; }}注意:- 构造函数严格控制状态,防止无效数据。- 实体的Id是身份核心,值对象没有。- 业务操作(如Pay)封装了业务规则。—### 三、进阶:引入领域服务与仓储接口当业务逻辑涉及多个实体或复杂流程时,我们可以使用领域服务(Domain Service)。同时,为了保持领域层的纯粹性,我们定义仓储接口(Repository Interface),但具体实现放在基础设施层。#### 代码示例2:领域服务与仓储接口csharp// 领域服务:处理订单创建和库存扣减的协作public class OrderService{ private readonly IProductRepository _productRepository; public OrderService(IProductRepository productRepository) { _productRepository = productRepository; } public Order CreateOrder(int productId, int quantity, Money price) { var product = _productRepository.GetById(productId); if (product == null) throw new Exception("产品不存在"); if (product.Stock < quantity) throw new Exception("库存不足"); // 扣除库存 product.DecreaseStock(quantity); _productRepository.Update(product); var total = new Money(price.Amount * quantity, price.Currency); return new Order(0, total, DateTime.Now); }}// 仓储接口:定义数据访问契约,不包含实现public interface IProductRepository{ Product GetById(int id); void Update(Product product);}解释:- 领域服务协调多个实体(如Product和Order)。- 仓储接口让领域层不依赖具体数据库技术,遵循依赖倒置原则。- 后续基础设施层(如EF Core)实现这些接口即可。—### 四、高级实践:领域事件与聚合根在复杂业务中,我们常使用**聚合根(Aggregate Root)来保证一致性,并通过领域事件(Domain Event)**解耦副作用。#### 聚合根示例假设一个Customer是聚合根,它的订单由Order组成。所有操作必须通过Customer进行,以保证数据一致性。csharppublic class Customer{ public int Id { get; private set; } private List<Order> _orders = new(); public IReadOnlyCollection<Order> Orders => _orders.AsReadOnly(); public void AddOrder(Order order) { if (order.TotalAmount.Amount > 10000) throw new Exception("订单金额超过限额"); _orders.Add(order); }}领域事件可用于发布“订单已创建”等通知,由应用层订阅并执行后续操作(如发送邮件)。—### 五、领域层设计原则总结1.保持纯粹:不引用任何框架或数据库技术。2.业务逻辑内聚:所有规则都应在实体或领域服务中实现。3.使用值对象管理不变性:如金额、日期范围。4.依赖倒置:通过接口让基础设施层依赖领域层。5.聚合根管理一致性:避免直接修改子实体。—### 六、完整示例:构建一个迷你订单系统为了将上述概念整合,我们提供一个完整的迷你示例(控制台应用),包含实体、值对象、领域服务以及简单的仓储。csharp// 程序入口class Program{ static void Main() { var productRepo = new InMemoryProductRepository(); var orderService = new OrderService(productRepo); // 创建产品 var product = new Product(1, "iPhone", 10); // 库存10 productRepo.Add(product); // 下单 var order = orderService.CreateOrder(1, 2, new Money(5000, "CNY")); Console.WriteLine($"订单创建成功,总金额:{order.TotalAmount.Amount} {order.TotalAmount.Currency}"); Console.WriteLine($"剩余库存:{product.Stock}"); }}// 产品实体public class Product{ public int Id { get; private set; } public string Name { get; private set; } public int Stock { get; private set; } public Product(int id, string name, int stock) { Id = id; Name = name; Stock = stock; } public void DecreaseStock(int quantity) { if (quantity < 0) throw new Exception("数量不能为负"); if (Stock < quantity) throw new Exception("库存不足"); Stock -= quantity; }}// 内存仓储实现(仅用于演示)public class InMemoryProductRepository : IProductRepository{ private Dictionary<int, Product> _products = new(); public Product GetById(int id) => _products.TryGetValue(id, out var p) ? p : null; public void Add(Product p) => _products[p.Id] = p; public void Update(Product p) => _products[p.Id] = p;}运行结果:订单创建成功,总金额:10000 CNY剩余库存:8—### 总结领域模型层是NLayerApp架构中表达业务规则和状态的核心。通过本篇文章,我们从基础的实体/值对象定义,到领域服务、仓储接口,再到聚合根和领域事件,逐步构建了一个完整的领域层设计视角。关键在于保持领域层的独立性,将业务决策集中于此,从而让整个系统更易维护和测试。在实践中,建议从简单的实体开始,逐步引入领域服务和事件,避免过度设计。记住,领域模型越健壮,上层应用就越简单,这正是NLayerApp的核心理念之一。希望本文能帮助你更好地理解并应用领域模型层。