Шаблоны и методы обеспечения кардинальности ассоциаций объектов

В последнее время я много думал об объектно-ориентированных принципах/практиках/парадигмах, таких как 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-интерфейсов, которые абстрагируют реальную реализацию объекта (объект 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 для обновления ссылок, однако их очень просто реализовать, и бизнес-ограничения встраиваются в классы бизнес-сущностей. Инкапсуляция принадлежащей сущности может усложнить модель предметной области, заставив сущности иметь описание, основанное на значении, но это очень чисто. Сторонний монитор изолирует явные ограничения количества элементов в отдельный класс, но также усложняет модель предметной области.

Есть ли у кого-нибудь другие мысли, идеи или лучшие подходы?


person Calvin Grunewald    schedule 28.09.2011    source источник


Ответы (1)


Создание ассоциаций не является обязанностью ни одного из классов. Предоставьте посреднику создать ссылку.

Создайте класс ассоциации WarehouseItem для представления ассоциации и класс WarehouseItemFactory для установления ассоциаций путем создания экземпляров WarehouseItem. WarehouseItemFactory будет отвечать за соблюдение правил кардинальности.

person Community    schedule 18.04.2012
comment
Это также можно сделать с помощью класса обслуживания, не устанавливая связи, но не требуя дополнительного класса WarehouseItem. С WarehouseItem вы должны защищать конструктор от использования кем-то другим, кроме WarehouseItemFactory, со службой вам придется защищать свойства, используемые для связывания экземпляров, от использования кем-то другим, кроме как службой. Итак, я думаю, моя точка зрения заключается в том, что создание еще одного класса и фабрики для его создания не принесет вам многого из того, что я вижу, и услуга может быть проще. - person jpierson; 07.11.2012
comment
Безусловно. Важным моментом является то, что ассоциация устанавливается классом, который имеет обзор как Warehouse, так и `Item' и понимает их правила. - person ; 09.11.2012