Як спроектувати сукупні межі?


10

Я хотів би написати заявку на кшталт електронної комерції.

І ви знаєте, що в подібних програмах продукти можуть мати різні властивості та особливості. Для імітації такої можливості я створив такі об'єкти доменної моделі:

Категорія - це щось на кшталт "електроніка> комп'ютери", тобто види продукції. Категорії містять перелік властивостей (Список <Властивість>).

Властивість - незалежна сутність, яка містить назву, одиниці виміру, тип даних. Наприклад, "ім'я", "вага", "розмір екрана". Одна і та ж властивість може мати різні продукти.

Продукт - просто містить ім'я та список значень, що стосуються властивостей. Значення - це об'єкт, що містить просто поле значення та ідентифікатор поля властивості.

Спочатку я вирішив у цій схемі зробити Категорію як єдиний агрегат, тому що, наприклад, коли я додаю новий продукт, мені потрібно знати всі дані, пов'язані з поточною категорією, включаючи властивості, пов'язані з поточною категорією ( category.AddNewProduct (product) ). Але що робити, коли мені просто потрібно додати нову властивість, яка не належить до жодної категорії. Наприклад, я не можу зробити цю категорію.AddNewProperty (властивість), оскільки це чітко говорить про те, що ми додаємо властивість до певної категорії.

На наступному кроці я вирішив розділити Властивість на окремий сукупність, але тоді це буде список з простими сутностями.

Звичайно, я можу створити щось на зразок PropertyAggregate, щоб зберігати всередині списку властивостей та правил господарювання, але коли я додаю товар, мені потрібно мати всередині цього списку весь список властивостей цієї категорії, щоб перевірити інваріанти. Але я також усвідомлюю, що зберігати ланки всередині сукупності на інших агрегатах - це погана практика.

Які варіанти оформлення цього ділового випадку?


Чи можете ви надати більш повний приклад категорії, властивості та продукту? Електроніка або комп’ютери були б категорією, iPhone X буде прикладом продукту, а властивість - що саме? 11 "дюймовий дисплей?
Ніл

ти майже правий. Я додав деякі уточнення
cephei

Здається, ви дивитесь на сукупний дизайн виключно з точки зору "контейнера даних". Ви також можете подумати про випадки використання вашої програми, беручи до уваги трансакційні аспекти, співпрацю / одночасний доступ, події, які відбуваються, переходи стану тощо
guillaume31

Відповіді:


7

З точки зору DDD Category, Productі Propertyвони є сутностями: всі вони відповідають об'єктам, які мають свою ідентичність.

Варіант 1: ваш оригінальний дизайн

Ви зробили Categoryкорінь єдиного сукупності. З одного боку, це має сенс, оскільки сукупність повинна забезпечувати узгодженість, коли об'єкти модифікуються, і Productповинна мати Propertiesйого Category:

введіть тут опис зображення

Але з іншого боку, єдиний агрегат означає, що всі його об'єкти пов'язані з коренем, який їм належить, і всі зовнішні посилання повинні бути зроблені за допомогою цього корінного сукупності. Це означає, що:

  • одна конкретна Productналежить одному і єдиному Category. Якщо Categoryвидалено, так це і його Products.
  • конкретна Propertyналежить одному і єдиному Category. Інакше сказано, якби "Екрани телевізорів" та "Комп'ютерні монітори" були б двома категоріями, "Екрани телевізорів: розмір" та "Комп'ютерні монітори: розмір" були б двома різними властивостями.

Другий момент не відповідає вашій розповіді: " Але що мені робити, коли мені просто потрібно додати нове Property, яке не належить до жодної категорії ". І незрозуміло, чи Propertiesможна використовувати одне і те саме в різних Categories.

Варіант 2: Властивість поза сукупністю

Якщо Propertyіснує незалежно від Categories, воно повинно бути поза сукупністю. І те саме, якщо ви хочете поділитися Propertiesміж ними Categories(що має сенс для висоти, ширини, розмірів тощо ...). Це, очевидно, так і є.

Наслідок - це зв'язок між Propertyречами та речами, що належать до сукупності: хоча ви можете переходити з внутрішньої частини сукупності до Property, вам більше не дозволяється переходити безпосередньо з а Propertyдо відповідних значень. Це обмеження навігації може бути показано на діаграмі UML:

введіть тут опис зображення

Зверніть увагу , що ця конструкція не заважає вам мати List<Property>ін Category, з посиланням семантичної (наприклад , Java): кожне посилання в списку відноситься до разделяемому Propertyоб'єкту в сховищі.

Єдина проблема цієї конструкції полягає в тому, що ви можете змінити Propertyабо видалити його: оскільки він знаходиться поза агрегатом, агрегат не може подбати про послідовність його інваріантів. Але це не проблема. Це наслідок принципів DDD та складності реального світу. Ось цитата Еріка Еванса в його семінарній книзі " Дизайн, керований доменом: вирішення складності в серці програмного забезпечення ":

Будь-яке правило, що охоплює АГРЕГАТИ , не очікується, що він буде оновлений постійно. Через обробку подій, пакетну обробку або інші механізми оновлення інші залежності можуть бути вирішені протягом певного визначеного часу. Але інваріанти, застосовані в рамках АГРЕГАТИ, будуть застосовані із завершенням кожної транзакції.

Так що, якщо ви зміните Property, вам доведеться переконатися, що служба перевіряє категорії, що посилаються на неї, оновлюються у міру необхідності.

Варіант 3: Категорія, властивості та товар у різних агрегатах

Мені просто цікаво, чи є обґрунтованим припущення, що Productналежить синглу Category:

  • Я часто бачу інтернет-магазини, які пропонують один із Productдекількох Categories. Наприклад, ви знайдете "Ноутбук марки X Model Y" під категорією "Ноутбуки" та категорії "Комп'ютери" та "багатофункціональний принтер Z" під категоріями "принтер", "сканер" та "факс".
  • Чи не можливо, що хтось створює Productперший, а лише пізніше призначає його Категоріям і заповнює значення?
  • Якщо ви хочете розділити категорію, ви б дійсно видалили її Продукти, а потім відтворили їх у нових категоріях?

Це не спростить агрегати, і у вас буде ще більше правил, що охоплюють агрегати. Але ваша система буде набагато більш надійним у майбутньому.


Дуже дякую, це дуже корисне пояснення. Але я хотів би уточнити кілька моментів. Я хотів би почати з другого варіанту, і хто знає, можливо, я підійду до третього. Якщо я вийду Propertyза межі Categoryсукупності, це означає, що Propertyстає сукупністю сама по собі і потребує сховище? Якщо це правда , то , як пройти потрібно List<Property>в Categoryразі? Через конструктор? Це буде правильно? І як я дізнаюся список Propertyідентифікаторів того, Categoryщо ще не створено?
cephei

@zetetic коротко: так, вам знадобиться незалежне сховище власності. Або ви передаєте список існуючих властивостей до фабрики Категорії, або створюєте порожні категорії та заповнюєте список методом addProperty. Питання взамін: уявіть, що ви хочете мати "обов'язкові" та "необов'язкові" властивості, а обов'язкова характеристика залежить від категорії. Як би ти впорався з цим?
Крістоф

Відповідаючи на ваше запитання, перше, що спадає на думку, - це те, що я можу створити спеціальну сутність, Featureі вона буде належати лише до Product. і ця організація не братиме участі у пошуку. що ти сказав ?
cephei

@zetetic чому б і ні! Я залишив би Значення, як вони зараз є у продукті, і став би асоціювати функцію з категорією. Категорія має n особливостей (частина її сукупності), властивість визначає m Особливості (але посилання переходить через функцію Категорія->). Потім ви розклали відносини "багато на багато" на більш керовані елементи, уточнивши сукупну межу. Нарешті про введення сховища: цього не потрібно, якщо ви посилаєтесь на інші агрегати за ідентичністю (читайте цю статтю informit.com/articles/article.aspx?p=2020371&seqNum=4 )
Крістоф

5

Як я бачу, ви можете вирішити це одним із двох способів:

Категорія - це особливий вид товару

Це означає, що для будь-якого продукту у вашій базі даних він містить зовнішній ключ, що вказує на той самий продукт таблиці. Продукт є продуктом лише в тому випадку, якщо немає товарів, зовнішній ключ яких дорівнює ідентичності цього продукту. Іншими словами, якщо в ньому немає продуктів, це продукт.

Це трохи спростить речі. Продукти до властивостей матимуть відношення "один до багатьох", а отже, і ваші категорії мають відношення "один до багатьох", оскільки вони також є продуктами. Додавання властивості до категорії було б так само просто, як і додавання властивості до продукту у вашій програмі. Завантаження всіх властивостей означало б поєднання властивостей продукту із властивостями асоційованого продукту категорії та вище, поки ви не досягнете продукту категорії без батьківського.

У вашій програмі електронної комерції потрібно було б розрізнити це, але якщо ви все одно завантажуєте продукти категорії, не знайте, чи маєте ви справу з категорією чи продуктом. Він також чудово піддається пошукам дерев до рівня продукту, оскільки кожен товар (категорія) відкриє список субпродуктів без особливих додаткових робіт.

Мінус цього - це, звичайно, додаткова інформація, присутня в продукті, яка не має сенсу для категорії, створила б незручні невикористані поля в продукті. Хоча це рішення було б більш гнучким у вашій програмі, воно також є дещо менш інтуїтивним.

Відносини багато до багатьох

Продукти більше не перебувають у складеному взаємозв'язку з майном. Ви створюєте таблицю ProductProperty з зовнішніми ключами таблиці продуктів і таблиці властивостей, які пов'язують ці два. Аналогічно, у вас є таблиця категорій, яка має багато-багато-множину з таблицею властивостей, і таблиця CategoryProperty із зовнішніми ключами таблиці категорії та таблиці властивостей.

Сам продукт матиме взаємозв'язок із категорією, що дозволяє по суті створити список унікальних властивостей, що стосуються як продукту, так і категорії за допомогою чітко оформленого оператора вибору.

З точки зору бази даних, це, безумовно, більш чисто та гнучкіше. Ваша заявка, ймовірно, може здійснюватися здебільшого, не маючи стосунку безпосередньо з CategoryProperty або ProductProperty, якщо запит виконано належним чином. Однак також не слід ставитися до категорії чи товару як до власника майна. Це має бути власна особа у вашій програмі. Це також означає, що управління зазначеними властивостями було б питанням створення власності, а потім пов'язування його з категорією чи продуктом у два окремі етапи. Безумовно, більше роботи, ніж перше рішення, але аж ніяк не складніше.

На додаток до цього, вам також доведеться провести додаткову перевірку при видаленні категорії або продукту, якщо якісь його властивості використовуються іншими (на відміну від першого рішення, де ви могли безпечно усунути всі пов'язані властивості даного товару / категорії) .

Висновок

У професійному контексті я б подолав категорію додаткових миль та відстань від продукту та товару від власності, використовуючи підхід «багато до багатьох». Не було б можливості перекриття даних, і в певному сенсі легше міркувати кожну з цих трьох як власну сутність. Однак, це жодним чином не є поганим рішенням, оскільки воно також дозволяє писати більш просту програму. Просто знайте, що якби ви думали, що вам може знадобитися врешті-решт перейти від одного рішення до іншого, ви, мабуть, просто буде у ваших інтересах вибрати друге.

Удачі!


Дякуємо за детальну та цікаву відповідь! на рівні бази даних, яку я вже моделював, як ви пояснили у другому випадку, ця закономірність називається суттю – атрибут – значення, але я застряг на рівні коду, а саме визначення агрегатів. У більшості випадків усі ці сутності використовуються разом. можна об'єднати в один сукупність, але є випадки, які люблять заповнення каталогів, які за сенсом вибиваються з сукупності.
cephei
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.