强制对象关联基数的模式和实践

发布于 2024-12-07 02:26:48 字数 1525 浏览 0 评论 0原文

我最近一直在思考面向对象的原则/实践/范式,例如 SOLID、Demeter 定律和 DDD,并且不断出现的一个主题是强制对象基数。

对象关联基数源自业务规则,该业务规则强制某些实体只能与一定数量的其他实体对象关联。例如,如果您正在设计一个管理仓库的系统,则业务规则可能是单个项目只能存储在一个仓库中。显然,在软件设计中强制执行这些规则是一个实现问题。

我想知道的是:如果业务领域需要严格的基数模型,那么执行它的最佳方法是什么?我能立即想到的技术包括以下内容:

  • 双向引用 - 关联对象之间的双向关联(对象 A 引用对象 B,对象 B 引用对象 A)

    类仓库 {
      私有列表<项目>项目;
    
      公共无效RegisterItem(项目对象){
        if(obj.仓库!= null)
          throw new ArgumentException(“只能注册未拥有的项目”)
    
        items.Add(obj);
        obj.Warehouse = this;
      }
    }
    
  • 封装拥有的实体 - 让所有者控制其创建和删除,并通过一组抽象实际实体实现的 API 提供访问权限(对象 A 克隆传入的实体 B 或根据传递的原理图创建实体 B)

    类仓库 {
      私有列表<项目>项目;
    
      公共无效RegisterItem(项目对象){
        items.Add((Item)obj.Clone());
      }
    
      公共无效RegisterItem(ItemDescriptor项目){
        items.Add(新项目(项目));
      }
    }
    
  • 第三方监视器 - 让一些了解基数约束的第三方适当地创建和连接对象关联(对象 C 知道 A 和 A 之间的关系) B 并负责创建和维护它- 此方法仅对C可用,对客户端不可用)

    类仓库 {
      私有列表<项目>项目;
    
      内部无效RegisterItem(项目对象){
        items.Add(obj);
      }          
    }
    
    类 WarehouseItemRegistrationService {
    
      私有列表<项目>注册物品;
    
      public void RegisterItem(仓库仓库, Item项目) {
        if(registeredItems.Contains(item))
          throw new ArgumentException("只能注册未拥有的项目");
    
        仓库.RegisterItem(项目);
      }
    }
    

我认为每种技术都有其优点和缺点。 双向关联会增加对象图的复杂性,并且需要私有 API 来更新引用,但实现起来非常简单,并将业务约束嵌入到业务实体类中。 封装拥有的实体可能会通过强制实体具有基于值的描述来使域模型复杂化,但它非常干净。 第三方监视器技术将显式基数强制隔离到单独的类,但它也使域模型变得复杂。

有没有人有任何其他想法、想法或更好的方法?

I've been thinking about object-oriented principals / practices / paradigms such as SOLID, Law of Demeter, and DDD a lot lately and a theme that continues to surface is enforcing object cardinality.

Object association cardinality is derived from business rules that mandate certain entities can only be associated with a certain number of other entity objects. For example, if you're designing a system to manage warehouses, a business rule could be that a single item can only be stored in one warehouse. Obviously, enforcing these rules within the software design is a matter of implementation.

What I'm wondering is this: in the event that a rigid cardinality model is required by the business domain, what is the best way to enforce it? The techniques I can think of off hand include the following:

  • Bi-directional references - Bi-directional associations between associated objects (object A references object B and object B references object 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;
      }
    }
    
  • Encapsulate the owned entity - let the owner control its creation and deletion and provide access through a set of APIs that abstract the actual entity implementation (object A clones a passed in entity B or creates an entity B based on a passed schematic)

    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));
      }
    }
    
  • Third party monitor - Have some third party that understands cardinality constraints create and hookup object associations appropriately (object C knows about the relationship between A and B and is responsible for creating and maintaining it - this method is only available to C and not available to clients)

    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);
      }
    }
    

I think each technique has its strengths and weaknesses. Bi-directional associations can add complexity to the object graph and require private APIs for updating references yet it is very simple to implement and embeds the business constraints in the business entity classes. Encapsulating the owned entity can complicate the domain model by forcing entities to have a value based description, yet it is very clean. The third party monitor technique isolates explicit cardinality enforcements to a separate class, but it also complicates the domain model.

Does anyone have any other thoughts, ideas, or better approaches?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

じ违心 2024-12-14 02:26:48

建立协会不是任何一个阶级的责任。将其留给调解人来创建链接。

创建一个关联类 WarehouseItem 来表示关联,并创建一个 WarehouseItemFactory 类,通过创建 WarehouseItem 实例来建立关联。 WarehouseItemFactory 将负责执行基数规则。

Establishing associations is not a responsibility of either class. Leave it to a mediator to create the link.

Create an association class WarehouseItem to represent the association and an WarehouseItemFactory class to establish the associations by creating instances of WarehouseItem. WarehouseItemFactory will be responsible for enforcing the cardinality rules.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文