开发者

Patterns and Practices for Enforcing Object Association Cardinality

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 as开发者_JAVA百科sociated 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?


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜