最近我一直在思考面向对象的原则/实践/范式,例如 SOLID、得墨忒耳定律和 DDD,并且不断出现的一个主题是强制对象基数。
对象关联基数源自要求某些实体只能与一定数量的其他实体对象相关联的业务规则。例如,如果您正在设计一个系统来管理仓库,则业务规则可能是单个项目只能存储在一个仓库中。显然,在软件设计中执行这些规则是一个实施问题。
我想知道的是:如果业务领域需要严格的基数模型,那么执行它的最佳方法是什么?我能想到的技术包括以下内容:
双向引用- 关联对象之间的双向关联(对象 A 引用对象 B,对象 B 引用对象 A)
class Warehouse { private List<Item> items; public void RegisterItem(Item obj) { if(obj.Warehouse != null) throw new ArgumentException("Can only register un-owned item") items.Add(obj); obj.Warehouse = this; } }
封装拥有的实体- 让拥有者控制其创建和删除,并通过一组 API 提供访问权限,这些 API 抽象了实际的实体实现(对象 A 克隆传入的实体 B 或基于传递的示意图创建实体 B)
class Warehouse { private List<Item> items; public void RegisterItem(Item obj) { items.Add((Item)obj.Clone()); } public void RegisterItem(ItemDescriptor item) { items.Add(new Item(item)); } }
第三方监视器- 让一些了解基数约束的第三方适当地创建和连接对象关联(对象 C 知道 A 和 B 之间的关系并负责创建和维护它 - 此方法仅对 C 可用,对客户端不可用)
class Warehouse { private List<Item> items; internal void RegisterItem(Item obj) { items.Add(obj); } } class WarehouseItemRegistrationService { private List<Item> registeredItems; public void RegisterItem(Warehouse warehouse, Item item) { if(registeredItems.Contains(item)) throw new ArgumentException("Can only register un-owned items"); warehouse.RegisterItem(item); } }
我认为每种技术都有其优点和缺点。双向关联会增加对象图的复杂性,并且需要私有 API 来更新引用,但实现起来非常简单,并将业务约束嵌入到业务实体类中。封装拥有的实体可以通过强制实体具有基于值的描述来使域模型复杂化,但它非常干净。第三方监控技术将显式基数强制隔离到一个单独的类中,但它也使域模型复杂化。
有没有人有任何其他想法、想法或更好的方法?