Об'єкти бізнесу - контейнери чи функціональні?


19

Це питання, яке я задав деякий час назад, так що це може бути краще обговорено тут ...

Там, де я працюю, ми неодноразово переходили на цю тему і шукаємо перевірку стану безпеки. Ось питання: чи повинні бізнес-об’єкти бути контейнерами даних (більше схожі на DTO ) чи вони також повинні містити логіку, яка може виконувати певну функціональність на цьому об'єкті.

Приклад - візьміть об’єкт клієнта, він, ймовірно, містить деякі загальні властивості (ім'я, ідентифікатор тощо), чи повинен об’єкт клієнта також включати функції (Save, Calc тощо)?

Один рядок міркування говорить, що відокремлюють об'єкт від функціональності (основна відповідальність) та розміщують функціональність у шарі або об'єкті Business Logic.

Інший рядок міркувань говорить, що ні, якщо у мене є клієнтський об’єкт, я просто хочу зателефонувати Клієнту. Збережіть, і це робити з цим. Чому мені потрібно знати про інший клас, щоб зберегти клієнта, якщо я споживаю об'єкт?

У наших останніх двох проектів об'єкти були відокремлені від функціональності, але знову було порушено дискусію щодо нового проекту.

Що має більше сенсу і чому ??


1
Не могли б ви розповісти більше про свій проект? Характер вашого проекту визначить, яке рішення краще.

Відповіді:


5

Якщо ви вважаєте, що Клієнт є частиною доменної моделі, то має сенс (особливо в контексті DDD, але не обмежується ним) мати як властивості, так і операції для цього об’єкта.

Однак, маючи на увазі, я думаю, що використаний вами приклад є поганим, і є причиною аргументу. Якщо ви говорите про наполегливість, то клієнти, як правило, не «рятують» себе; все, що ви використовуєте для наполегливості. Має сенс, що будь-який тип наполегливості повинен належати шару / перегородці стійкості. Це, як правило, мислення за схемою сховища. ** Такий метод, як Customer.UpgradeWarranty () або Customer.PromoteToPreferred (), робить аргумент зрозумілішим.

Це також не виключає можливості наявності DTO . Розглянемо ситуацію, коли ти збираєшся, наприклад, передавати інформацію про клієнта віддаленій службі. Замовник може не мати сенсу створювати собі DTO для транспорту, це питання архітектури, але це може бути зроблено для цього в стійкості або мережевому шарі / розділі / коді / що-у вас є. У такому випадку такий об'єкт може мати методи, схожі на це

public static CustomerDTO GetDTO(Customer c) { /* ... */ }

public static Customer GetCustomer(CustomerDTO cdto) { /* ... */ }

Отже, підсумовуючи, має сенс робити операції над об’єктом домену, які відповідають стандартам логічних операцій у домені.

Google для "Непохитного наполегливості" для багатьох хороших дискусій з цього питання ( це питання ТАК , і його прийнята відповідь - хороше місце для початку).

** Це стає дещо затуманено певним програмним забезпеченням OR / M, коли ви змушені успадковувати постійну базу, яка має метод "Зберегти".


3

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

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


3

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

Отже, я б запитав себе у вашому конкретному випадку: чи повинен клієнт знати, як заощадити себе?

Для мене відповідь була б ні: логічно для мене це не має сенсу, і замовник не повинен взагалі нічого знати про будь-яку стійкість (розподіл обов'язків).

Що стосується прикладів SnOrfus із Customer.UpgradeWarranty () або Customer.PromoteToPreferred (), вони, очевидно, більше орієнтовані на бізнес-логіку, ніж Customer.Save (). До цього існують різні підходи, але знову ж таки, якщо ви запитаєте себе, чи повинен замовник мати змогу оновити гарантію, відповідь може бути і так, ні, залежно від того, як ви на це дивитесь:

  • так: замовник може, звичайно, оновити гарантію
  • ні: клієнт може попросити оновити, але оновлення здійснює хтось інший

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

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


2

Думаю, ви конкретно говорите про різницю між ActiveRecordшаблоном і Repositoryсхемою. У перших суб’єкти знають, як зберігати себе, а в другому сховище знає про наполегливість. Я думаю, що останнє пропонує краще розділити проблеми.

У більш широкому розумінні, якщо сутності діють більше, як структура даних, то вони не повинні мати поведінки, але якщо вони мають поведінку, то вони не повинні використовуватися як структура даних. Приклад:

Структура даних:

class CustomerController
{
    public int MostRecentOrderLines(Customer customer)
    {
        var o = (from order in customer.Orders
                orderby order.OrderDate desc
                select order).First();
        return o.OrderLines.ToList().Count;
    }
}

Структура без даних:

class Customer
{
    public int MostRecentOrderLines()
    {
        // ... same ...
    }
}

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

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


1

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

Я спробую узагальнити факти, які вони викладають:

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

  • Простіше зрозуміти код та функціональність бу-об’єкта.

  • Менша складність в дизайні

Я кажу їм, що вони ледачі, і я зробив би це так:

  • Так, бізнес-класи представляють речі, тому вони містять дані. Але почувати себе неправильно, щоб зберегти себе або навіть скопіювати. Ви не можете це зробити в rl.

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

  • Маючи один об'єкт, здатний зберігати дані, цей об’єкт може утримувати з'єднання з базою даних, і весь трафік бази даних керується цим об’єктом. (в основному це рівень доступу до даних), інакше всі об’єкти Business повинні мати з'єднання. (що додає складності)

Ну так чи інакше, я збираюся запитати вчителя. Коли я це зробив, я опублікую його відповідь і тут, якщо ви хочете. ;)

редагувати:

Я забув згадати, що цей проект стосувався магазину книг.


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

1

Відповідь дійсно залежатиме від того, яка ваша архітектура / дизайн - архітектура DDD з доменною моделлю буде сильно відрізнятися від CRUD-орієнтованої на даних моделі, коли справа стосується дизайну об'єктів.

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

У доменній моделі ви хочете відокремити бізнес-модель від проблем інфраструктури - тому ви абсолютно хочете уникати таких методів, як ".Save". Я не пам'ятаю востаннє, коли я "врятував" клієнта в реальному житті!

У додатку CRUD тоді дані є громадянами першого класу, тому ".Зберегти" цілком підходить.

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


0

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

Я б також модифікував точку Скотта Вітлока зверху (за винятком того, що я не маю жодних точок бути новим членом), дані або класи бізнес-логіки не повинні насправді турбуватися про те, як об’єкт зберігається постійно.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.