Анемія – English page. Анемічна модель предметної області – не антишаблон, а архітектура за принципами SOLID

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

Значення поняття

Гемоглобін є основною частиною еритроцитів. У його складі є іон заліза, що зв'язує кисень. При нестачі червоних кров'яних тіл в організмі поступово настає анокс (гіпоксія). Симптомами анемії у разі виступають втома, головний біль, задишка. Малокров'ю з міжнародної класифікації хвороб надано код МКБ-10, згідно з даними МОЗ РФ у 15% населення виявляється ця патологія. Найбільш схильні до неї вагітні (40%), на наступному місці в групі ризику знаходяться діти до 2 років (18-25%).

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

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

Етіологія захворювання

Малокровість діагностується у пацієнтів і натомість виявлення різних чинників. Відомі такі основні причини анемії:

  1. Втрата великого об'єму крові при тяжкому менструальному циклі, глибоких ранах, на тлі злоякісного раку товстої кишки, кишкових виразок.
  2. Дисфункція нирок, при якій знижується виробництво кісткового мозку еритропоетину, що виробляє ретикулоцити (попередники еритроцити).
  3. Захворювання може передатися у спадок від родичів першої лінії.
  4. Нераціональне харчування, дефіцит вітамінів групи В12 та С, фолієвої кислоти, заліза.
  5. Анемія розвивається і натомість хронічних патологій: хвороба Крона, СНІД, ВІЛ, ревматоїдний артрит, карцинома.
  6. Прояв ознак ураження кровотворної системи пов'язаний і з психосоматикою. Анемія виступає як специфічний сигнал організму про те, що людина надмірно самокритична, незадоволена своїм життям. У цьому випадку психологи рекомендують подумки повторювати подумки, що новий шлях і думки не несуть загрози та абсолютно безпечні.
  7. Організм деяких людей не здатний засвоювати вітамін В12, що призводить до розвитку недокрів'я. Зменшення всмоктування корисних речовин можуть зумовити молочні продукти, тверду їжу, злаки у сирому вигляді.
  8. За відсутності захворювань еритроцити мешкають 100 днів. При поразці селезінки розвивається гемоліз, у якому порушується їх функціонування.
  9. Етанол токсичний для мозкової діяльності та уповільнює продукцію еритроцитів. При поєднанні цих факторів у хронічних алкоголіків суттєво підвищуються ризики розвитку анемії.
  10. Виснаження внутрішніх резервів заліза провокується найчастіше у жінок, які борються із зайвою вагою і дотримуються суворих дієт.
  11. Анемія нерідко проявляється у передопераційному періоді. Тому хірург повинен оцінити повною мірою ризик втручання та підвищити рівень гемоглобіну до норми, щоб знизити навантаження на серцево-судинну систему.

Останнє оновлення: 19.07.2016

Одним з ключових компонентів патерну MVC є моделі. Ключове завдання моделей - опис структури та логіки даних, що використовуються.

Як правило, всі використовувані сутності у додатку виділяються в окремі моделі, які описують структуру кожної сутності. Залежно від завдань та предметної області, ми можемо виділити різну кількість моделей у додатку.

Усі моделі оформляються як звичайні POCO-класи (plain-old CRL objects), тобто звичайні класи мовою C#. Наприклад, якщо ми працюємо з додатком інтернет-магазину мобільних телефонів, то ми могли б визначити в проекті таку модель, яка представляє телефон:

Public class Phone (public int Id (get; set;) public string Name (get; set;) public string Company (get; set;) public int Price (get; set;))

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

Однак модель необов'язково має складатися лише з властивостей. Крім того, вона може мати конструктор, будь-які способи, поля, взагалі представляти стандартний клас мовою C #. Моделі, які також визначають поведінку, на противагу анемічним моделям називають "товстими" моделями (Rich Domain Model/Fat Model/Thick Model). Наприклад, ми можемо уникнути анемічної моделі, модифікувавши її так:

Public class Phone ( private decimal _discount = 0; public Phone (decimal discount) ( this._discount = discount; ) public int Id ( get; set; ) public string Name ( get; set; ) public string Company ( get; set; ) public decimal Price ( get; set; ) public decimal GetPriceWithDiscount() ( return this.Price - (this.Price * this._discount); ) )

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

У ASP.NET MVC Core моделі можна розділити за ступенем застосування на кілька груп:

    Моделі, об'єкти яких зберігаються у спеціальних сховищах даних (наприклад, у базах даних, файлах xml тощо)

    Моделі, які використовуються для передачі даних подання або навпаки для отримання даних з подання. Такі моделі ще називаються моделями подання

    Допоміжні моделі для проміжних обчислень

Як правило, для зберігання моделей створюється у проекті окрема папка Models. Моделі вистави нерідко поміщаються в окрему папку, яка нерідко називається ViewModels.

Проект ASP.NET MVC Core із вбудованою автентифікацією за замовчуванням вже містить ці папки, і в них знаходяться всі необхідні моделі. Однак, якщо ми створюємо проект без вбудованої аутентифікації, то ці папки відсутні. І, відповідно, нам треба додати ці папки вручну. Але знову ж таки підкреслю, що нам необов'язково називати папки для зберігання моделей саме Models і ViewModels. Це можуть бути каталоги з будь-якими назвами, можна поміщати моделі в корінь проекту, але найпоширенішим стилем є назви Models та ViewModels.

Наприклад, створимо новий проект ASP.NET Core на кшталт Web Application і назвемо його ModelsApp. Спочатку додамо до проекту папку Models для зберігання моделей.

І в неї помістимо новий клас Company:

Public class Company ( public int Id ( get; set; ) public string Name ( get; set; ) public string Country ( get; set; ) )

Також додамо в папку Models клас Phone

Public class Phone (public int Id (get; set;) public string Name (get; set;) public Company Manufacturer (get; set;) public decimal Price (get; set;))

Ці моделі будуть описувати дані, які ми будемо використовувати. Ці дані можуть зберігатися в базі даних, але для простоти ми визначимо їх у контролері. Змінимо контролер HomeController наступним чином:

Using System.Collections.Generic; використовуючи System.Linq; using Microsoft.AspNetCore.Mvc; using ModelsApp.Models; // простір імен моделей namespace ModelsApp.Controllers ( public class HomeController: Controller ( List компанії; List Phones; Public HomeController() ( Company apple = New Company ( Id = 1, Name = "Apple", Country = "США")); ; Company google = new Company ( Id = 3, Name = "Google", Country = "США" ); companies = new List (apple, microsoft, google); phones = new List (new Phone (Id=1, Manufacturer=apple, Name="iPhone 6S", Price=56000), new Phone (Id=2, Manufacturer=apple, Name="iPhone 5S", Price=41000), new Phone ( Id=3, Manufacturer=microsoft, Name="Lumia 550", Price=9000), новий Phone (Id=4, Manufacturer=microsoft, Name="Lumia 950", Price=40000), new Phone (Id=5, Manufacturer = google, Name = "Nexus 5X", Price = 30000), новий Phone (Id = 6, Manufacturer = google, Name = "Nexus 6P", Price = 50000)); ) Public IActionResult Index() ( return View(phones); ) ) )

Список об'єктом моделі передається у виставу за допомогою методу View() .

І наприкінці змінимо уявлення Index.cshtml, яке виводитиме всі об'єкти:

@using ModelsApp.Models @model IEnumerable @( ViewData["Title"] = "Home Page"; )

@foreach (Phone p in Model) ( }
@p.Name@p.Manufacturer?.Name@p.Price

Від перекладача: На проекті, де я працюю, зараз відбувається активне переписування логіки, раніше реалізованої у вигляді багатої моделі предметної області (з використанням Active Record та Unit of Work). Новий підхід включає класи сутностей без поведінки і служб без стану, що взаємодіють за допомогою інтерфейсів - фактично, він являє собою анемічну модель, з перспективою переходу в подальшому на мікросервісну архітектуру. Спостерігаючи в режимі реального часу, як «макаронний монстр» приблизно з півтора мільйона LOC поступово набуває форми, як спрощуються тестування, масштабування і кастомізація системи під потреб різних замовників, я був дуже здивований, дізнавшись, що такий підхід часто розглядається як архітектурний анти-шаблон . Намагаючись розібратися в причинах цього, я наткнувся на цю статтю і розміщую її переклад, щоб обговорити з спільнотою плюси і мінуси підходу.

Шаблони проектування, анти-шаблони та анемічна модель предметної області

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


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


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


Я переконаний, що одним з таких анти-шаблонів, що незаслужено відкидаються, є Анемічна модель предметної області (АМПО, Anaemic Domain Model), описана Мартіном Фаулером і Еріком Евансом. Обидва автори описують цей шаблон як нездатність змоделювати предметну область в стилі об'єктно-орієнтованому, через що бізнес-логіка описується в процедурному стилі. Такий підхід протиставляється Багатій моделі предметної області (БМПО, Rich Domain Model), - у ній класи, що представляють сутності предметної області, містять у собі дані, і всю бізнес-логіку. Так, анемічна модель може бути невдалим вибором для деяких систем, але зовсім не факт, що те саме справедливо для будь-яких систем. У цій статті я розглядаю аргументи, що висуваються проти анемічної моделі, і обґрунтовую, чому в ряді сценаріїв АМПО виглядає розумним вибором з точки зору відповідності принципам SOLID, сформульованим Робертом Мартіном (, ), - принципам, в яких укладено рекомендації щодо досягнення балансу між простотою масштабованістю та надійністю при розробці ПЗ. Вирішуючи гіпотетичну проблему і порівнюючи анемічні і багаті моделі, я маю намір показати, що АМПО краще відповідає принципам SOLID. Тим самим я хочу оскаржити категоричну думку про цей підхід, нав'язану авторитетами, і показати, що використання АМПО – насправді придатне архітектурне рішення.

Чому анемічну модель предметної області вважають антишаблоном?

Фаулер і Еванс описували АМПО як сукупність класів без поведінки, містять дані, необхідні моделювання предметної області. У цих класах практично немає (або немає зовсім) логіки щодо валідації даних на відповідність бізнес-правилам. Натомість, бізнес-логіка полягає в шарі служб, який складається з типів та функцій, що обробляють елементи моделі відповідно до бізнес-правил. Основний аргумент проти такого підходу полягає в тому, що дані та способи їхньої обробки виявляються розділені, що порушує один із фундаментальних принципів об'єктно-орієнтованого підходу, т.к. не дозволяє моделі забезпечувати власні інваріанти. На противагу цьому, хоча БМПО і складається з того ж набору типів, що містять дані про предметну галузь, - але вся бізнес-логіка також полягає в цих сутностях, будучи реалізованою у вигляді методів класів. Таким чином, БМПО добре узгоджується з принципами інкапсуляції та приховування інформації. Як було зазначено Майклом Скоттом в: «Завдяки інкапсуляції, розробники можуть об'єднувати дані та операції з їхньої обробки в одному місці, а також приховувати непотрібні деталі від користувачів узагальненої моделі».


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


Не слід забувати, однак, що здатність моделі забезпечувати виконання певних обмежень, що накладаються на дані, - це лише одна з безлічі властивостей, якими повинна володіти система. Нехай АМПО жертвує можливістю валідації на рівні окремих бізнес-сутностей, але натомість вона дає неймовірну гнучкість та простоту підтримки системи в цілому завдяки тому, що реалізація логіки винесена у вузькоспеціалізовані класи, а доступ до них здійснюється через інтерфейси. Ці переваги мають особливо велике значення у мовах зі статичною типізацією, таких як Java чи C# (у яких поведінка класу може бути змінено під час виконання програми), т.к. покращують тестування системи шляхом введення явних «швів» (, ) з метою усунення надмірної зв'язаності.

Простий приклад

Давайте представимо серверну частину інтернет-магазину, де клієнт може як купувати товари, так і виставляти на продаж товари для інших клієнтів з усієї земної кулі. Придбання товару призводить до зменшення коштів у рахунку покупця. Подумаємо, як можна реалізувати процес розміщення клієнтом замовлення на придбання товару. Відповідно до вимог, клієнт може розмістити замовлення, якщо в нього а) достатньо коштів на рахунку, та б) товар доступний у регіоні клієнта. При використанні БМПО, клас Customerописуватиме сутність «Клієнт»; він буде включати всі властивості клієнта та такі методи як PurchaseItem(Item item)(Купити товар). Аналогічно, класи Itemі Orderпредставляють моделі предметної області, що описують сутності Товар та Замовлення, відповідно. Реалізація класу Customer(на псевдо-C#) може бути приблизно такою:


/*** КОД З ВИКОРИСТАННЯ БМПО ***/ class Customer: DomainEntity // Базовий клас, що надає CRUD-операції ( // Опускаємо оголошення закритих членів класу public bool IsItemPurchasable(Item item) ( bool shippable = item.ShipsToRegion(this). Region); return this.Funds >= item.Cost && shippable; ) public void .Funds -= item.Cost; this.Update(); ) ) ) /*** КІНЕЦЬ КОДУ З ВИКОРИСТАННЯ БМПО ***/

Сутності предметної області реалізуються з допомогою шаблону Active Record , у якому використовуються методи Create/Read/Update/Delete (реалізовані лише на рівні фреймворку чи базового класу), дозволяють змінювати записи у шарі зберігання даних (наприклад, у базі даних). Передбачається, що метод PurchaseItemвикликається в рамках транзакції, що здійснюється над сховищем даних та керується ззовні (наприклад, вона може відкриватися в обробнику HTTP-запиту, який витягує інформацію про клієнта та товар безпосередньо з переданих у запиті параметрів). Виходить, що в нашій БМПО роль сутності «Клієнт» полягає 1) у поданні моделі даних, 2) реалізації бізнес-правил, 3) створенні сутності «Замовлення» для здійснення покупки та 4) взаємодії із шаром зберігання даних за допомогою методів, визначених для Active Record. Воістину, «багатству» такої моделі позаздрив би цар Крез, адже ми розглядали досить простий варіант використання.


Наступний приклад ілюструє, як та ж логіка могла б бути виражена засобами АМПО, в тих же умовах:


/*** КОД З ВИКОРИСТАННЯМ АМПО ***/ class Customer ( /* Some public properties */ ) class Item ( /* Some public properties */ ) class IsItemPurchasableService: IIsItemPurchasableService ( ItemShippingRegionService shipsToRegion item) ( bool shippable = shipsToRegionService.ShipsToRegion(item); return customer.Funds >= item.Cost && shippable; ) ) class PurchaseService: IPurchaseService ( ICustomerRepository customers; IOrderFactory orderFactory; IOrderRepository orders; IIsItemPurchasableService isItemPurchasableService; // Конкретные экземпляры инициализируются в конструктор public void PurchaseItem(Customer customer, Item item) ( if (isItemPurchasableService.IsItemPurchasable(customer, item)) ( Order order = orderFactory.CreateOrder(customer, item); orders.Insert(order.) cu; Cost;customers.Update(customer); ) ) ) /*** КІНЕЦЬ КОДУ З ВИКОРИСТАННЯМ АМПО ***/

Порівняння прикладів реалізації з погляду відповідності принципам SOLID

На перший погляд, АМПО вочевидь програє БМПО. У її реалізації використано більше класів, а логіка розмазана за двома доменними службами ( IPurchaseServiceі IItemPurchasableService) та ряду служб додатку ( IOrderFactory, ICustomerRepositoryі IOrderRepository) замість того, щоб розташовуватися в межах моделі предметної області. Класи предметної області тепер не містять жодної поведінки, а лише зберігають дані і допускають зміну свого стану поза рамками накладених обмежень (і - о жах! - втрачають здатність забезпечувати власні інваріанти). Враховуючи всі ці явні недоліки, як взагалі можна розглядати таку модель як конкурента більш об'єктно-орієнтованої БМПО?


Причини, з яких АМПО є чудовим вибором для даного сценарію, випливають із розгляду принципів SOLID та їх накладення на обидві архітектури, що розглядаються. "S" означає "Принцип єдиної відповідальності" (Single Responsibility Pronciple, ), який говорить, що клас повинен робити тільки щось одне - але робити це добре. Зокрема, клас має реалізовувати лише одну абстракцію. "O" - "Принцип відкритості/закритості" (Open/Closed Principle, ), постулат про те, що клас повинен бути "відкритим для розширення, але закритим для зміни". Це означає, що при розробці класу треба максимально прагнути того, щоб реалізацію не довелося змінювати в майбутньому, тим самим зводячи до мінімуму наслідки змін, що вносяться.


Здавалося б, клас Customerу БМПО реалізує єдину абстракцію «Клієнт», але насправді цей клас відповідає за багато речей. Цей клас моделює ідані, ілогіку в рамках однієї і тієї ж абстракції, незважаючи на те, що бізнес-логіка має звичай змінюватися набагато частіше, ніж структура даних. Цей клас створює і ініціалізує сутності «Замовлення» в останній момент здійснення покупки, і навіть містить логіку, визначальну, чи може клієнт здійснити покупку. А надаючи базові CRUD-операції, визначені в базовому класі, сутність предметної області «Клієнт» виявляється ще пов'язаною з тією моделлю сховища даних, яка підтримується базовим класом. Варто нам перерахувати всі ці обов'язки, як стало очевидним, що сутність Customerв БМПО є прикладом слабкого поділу відповідальності.


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

Порівняння гнучкості рішень на базі багатої та анемічної моделей предметної області

Розглянемо приклади сценаріїв, за яких нам довелося б змінювати клас Customerв БМПО.

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

Тепер розглянемо сценарії, у яких необхідно змінити типи, описані в АМПО. Класи бізнес-сутностей, призначення яких полягає в моделюванні предметної області, підлягають зміні тоді і тільки тоді, коли змінюються вимоги до складу даних. У разі ускладнення правил, за якими визначається можливість придбання того чи іншого товару (наприклад, для товару вказується мінімально допустимий рейтинг довіри клієнта, якому цей товар може бути проданий), зміні підлягає тільки реалізація IIsItemPurchasableService, тоді як при використанні БМПО нам довелося б відповідним чином змінювати клас Customer. Якщо змінюються вимоги до сховища даних - в АМПО завдання вирішується шляхом передачі в PurchaseServiceз вищого класу служб докладання нової реалізації існуючого інтерфейсу репозиторію , не вимагаючи модифікації існуючого коду; в БМПО так легко не відбутися, модифікація базового класу торкнеться всіх класів бізнес-сутностей, успадкованих від нього. У випадку, коли для створення екземпляра класу Orderнеобхідно передати додатковий параметр, реалізація IOrderFactoryможе виявитися в змозі забезпечити цю зміну, не впливаючи на PurchaseService. В анемічній моделі у кожного класу єдина відповідальність, і вносити зміни до класу доведеться лише за зміни відповідної вимоги в предметній області (або пов'язаної інфраструктури).


А зараз уявімо, що для реалізації нової бізнес-вимоги ми маємо забезпечити можливість повернення коштів, якщо клієнт не задоволений покупкою. У багатій моделі це можна було б реалізувати шляхом додавання методу RefundItemдо сутності «Клієнт», аргументуючи це тим, що вся логіка, що стосується клієнта, виявляється укладеною по суті Customer. Проте процедура повернення коштів сильно відрізняється від процедури здійснення покупки, відповідальність за яку раніше була покладена на клас Customer, і в результаті ми отримуємо ще більше змішання відповідальності у межах одного типу. Виходить, у класах багатої моделі можуть накопичуватися слабко пов'язані елементи бізнес-логіки, підвищуючи складність їхньої структури. В анемічній моделі механізм повернення коштів можна реалізувати шляхом створення нового класу RefundService, який реалізовуватиме лише логіку, що безпосередньо відноситься до повернень. Цей клас може залежати від кількох інших абстракцій (тобто інтерфейсів інших доменних та інфраструктурних служб), необхідних для виконання своїх обов'язків. Звернення до методів класу RefundServiceможе походити з вищих рівнів (у відповідь на запит про здійснення повернення коштів), і виходить, що реалізацію нового сценарію вдалося виконати без жодного впливу на раніше розроблену функціональність.


У розглянутому прикладі проблема закріплення за одним класом не пов'язаних між собою відповідальності, з якою ми зіткнулися в БМПО, ефективно вирішується в анемічній моделі за допомогою букв I та D з абревіатури SOLID. Це, нагадаю, «Принцип поділу інтерфейсу» (Interface Segregation Principle, ) і «Принцип інверсії залежностей» (Dependency Inversion Principle, ). Вони стверджують, що інтерфейси повинні бути наборами сильно зчеплених методів, і що інтерфейси повинні використовуватися для з'єднання частин системи воєдино (у разі АМПО - з'єднання служб доменного шару між собою). Наслідування принципу поділу інтерфейсу, як правило, дає в результаті невеликі, вузькоспеціалізовані інтерфейси - такі як IItemShippingRegionServiceі IIsItemPurchasableServiceз нашого прикладу або інтерфейс абстрактного репозиторію. Принцип інверсії залежностей змушує нас спиратися ці інтерфейси, щоб одна служба не залежала від деталей реалізації інший.

Анемічна модель предметної області найкраще підтримує автоматизоване тестування

Більш гнучка і податлива структура додатка, а також дотримання вищезазначених принципів дозволяють анемічній моделі проявити свої переваги над БМПО у спрощенні автоматизованого тестування. Сильно зчеплені, але слабко пов'язані між собою компоненти спілкуються за допомогою інтерфейсів і збираються воєдино за допомогою впровадження залежностей, що дозволяє без особливих зусиль підміняти залежності «пустушками», mock-об'єктами. Звідси в АМПО нескладно реалізовувати такі сценарії для автоматизованого тестування, які було б набагато важче реалізувати в рамках БМПО, тим самим покращується простота підтримки автоматизованих тестів. При зниженні вартості автоматизованих тестів розробники більш охоче створюють і підтримують їх в актуальному стані. Як ілюстрація, спробуємо розробити модульний тест для методу IsItemPurchasable.


Відповідно до пред'явлених вимог, товар вважається доступним для покупки, якщо клієнт має достатньо коштів на рахунку, і він знаходиться в регіоні, куди цей товар може бути доставлений. Припустимо, ми пишемо тест, перевіряючий, що й у клієнта достатньо коштів у рахунку, але не перебуває у регіоні, куди здійснюється доставка цього товару, цей товар недоступний на купівлю. У БМПО такий тест, ймовірно, включав би створення екземплярів Клієнт ( Customer) та Товар ( Item), налаштування Клієнта таким чином, щоб кошти на його рахунку перевищували вартість Товару, та щоб його регіон не входив до переліку регіонів, куди цей товар доставляється. Після чого ми мали б переконатися, що customer.IsItemPurchasable(item)повертає значення false. Проте метод IsItemPurchasableзалежить від деталей реалізації методу ShipsToRegionкласу Item. Зміна бізнес-логіки, що стосується товару, призведе до зміни результатів цього тесту. Такий ефект небажаний, оскільки цей тест повинен перевіряти виключно логіку, укладену у класі. Customer, а логіка методу ShipsToRegion, Укладена по суті «Товар», повинна покриватися окремим тестом. Оскільки бізнес-логіка полягає в сутності, що описують предметну область і надають відкритий інтерфейс для доступу до укладеної в них логіки, класи виявляються сильно пов'язаними, що призводить до лавиноподібного ефекту при внесенні змін, через що автоматизовані тести стають крихкими.


З іншого боку, в АМПО логіка методу IsItemPurchasableвинесено до окремої спеціалізованої служби, яка залежить від абстрактних інтерфейсів (метод IItemShippingRegionService.ShipsToRegion). Для тесту, що розглядається, ми можемо просто створити заглушку для IItemShippingRegionService, в якій буде реалізовано метод ShipsToRegion, що завжди повертає false. Розділивши бізнес-логіку ізольованими модулями, ми захистили кожну частину від змін деталей реалізації в інших частинах. На практиці це означає, що невелика зміна логіки швидше за все призведе до «падіння» лише тих тестів, які безпосередньо перевіряють поведінку того коду, в який були внесені зміни, що можна використовувати для перевірки правильності нашого уявлення про код, що змінюється.

Рефакторинг БМПО з метою дотримання принципів SOLID призводить до «анемії» моделі

Прихильники архітектури, що використовує БМПО, можуть заперечити, що описаний гіпотетичний приклад відповідає «справжньої» багатої моделі. Вони скажуть, що у правильно реалізованої багатої моделі не можна змішувати сутності предметної області із завданнями їх запису в сховище - натомість краще використовувати об'єкти передачі (DTO, Data Transfer Object, , ), з яких відбувається обмін із шаром зберігання даних. Вони рознесуть у пух і порох ідею прямого виклику конструктора класу Orderбезпосередньо з логіки класу Customer- Зрозуміло, в жодній осудній реалізації сутності предметної області не викликатимуть конструктор безпосередньо, здоровий глузд змушує використовувати фабрику! Але на мою думку, це виглядає як спроба застосовувати потужність принципів SOLID до інфраструктурних служб, при повному їх ігноруванні в додатку до моделі предметної області. Якщо нашу гіпотетичну БМПО рефакторити для відповідності принципам SOLID, буде виділено дрібніші сутності: з сутності Клієнт може бути виділено сутності «Покупка клієнта» ( CustomerPurchase) і «Повернення грошей клієнта» ( CustomerRefund). Але може статися, що й нові моделі, як і раніше, залежатимуть від елементарних бізнес-правил, що змінюються незалежно одна від одної, а від них, у свою чергу, залежатимуть інші сутності. Щоб уникнути дублювання логіки і сильної зв'язаності класів, ці правила доведеться і далі рефакторити, виділяючи їх в окремі модулі, доступ до яких здійснюється за допомогою інтерфейсів. У результаті багата модель, відрефакторена до повної відповідності принципам SOLID, прагне стану анемічної моделі!

Висновок

Дослідивши реалізацію простого прикладу, дійшли висновку, що анемічна модель предметної області ближче відповідає принципам SOLID, ніж багата модель. Ми побачили переваги, які дають відповідність принципам SOLID: слабку зв'язаність і сильну зчепленість, що підвищують гнучкість архітектури програми. Свідченням зростання гнучкості стало поліпшення тестованості програми через легкість реалізації «заглушок» для залежностей. Розглядаючи шляхи досягнення цих самих якостей у рамках БМПО, ми виявили, що рефакторинг багатої моделі закономірно призводить до її «анемічності».


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

Посилання

Розгорнути

Evans, Eric. Domain-driven design: tackling complexity в heart of software. Addison-Wesley Professional, 2004.


Martin, Robert C. Principles of Object-Oriented Design. http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod, 2005.


Martin, Robert C. Design principles and design patterns. Object Mentor, 2000: 1-34.


Erich, Gamma, et al. Design patterns: elements of reusable object-oriented software. Addison Wesley Publishing Company, 1994.


Wolfgang, Pree. Design patterns for object-oriented software development. Addison-Wesley, 1994.


Rising, Лінда. Тексти handbook: techniques, strategies, and applications. Vol. 13. Cambridge University Press, 1998.


Budgen, David. Software design. Pearson Education, 2003.


Scott, Michael L. Programming language pragmatics. Morgan Kaufmann, 2000.


Hevery, Мішко. Writing Testable Code. http://googletesting.blogspot.co.uk/2008/08/by-miko-hevery-so-you-decided-to.html , Google Testing Blog, 2008.


Osherove, Roy. The Art of Unit Testing: З Examples in. Net. Manning Publications Co., 2009.


Martin, Robert C. Agile software development: principles, patterns, and practices. Prentice Hall PTR, 2003.


Martin, Robert C. SRP: The Single Responsibility Principle. , Object Mentor, 1996.


Martin, Robert C. The Open-Closed Principle. , Object Mentor, 1996.


Martin, Robert C. Interface Segregation Principle. , Object Mentor, 1996.


Martin, Robert C. Dependency Inversion Principle, Object Mentor, 1996.


Fowler, Martin. Patterns of enterprise application architecture. Addison-Wesley Longman Publishing Co., Inc., 2002.


Fowler, Martin. Data Transfer Object. http://martinfowler.com/eaaCatalog/dataTransferObject.html , Martin Fowler site, 2002.

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

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

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

Класифікація анемій
Класифікація анемійпроводиться за низкою показників.

1). За механізмом розвитку:

1) анеміївнаслідок крововтрат (постгеморагічні);

2) анеміївнаслідок посиленого кроворуйнування (гемолітичні);

3)анеміївнаслідок порушеного кровотворення, які у свою чергу поділяються на:

а) залізодефіцитні;

б) порфіринодефіцитні;

в) В12 фолієво-дефіцитні;

г) гіпо-, апластичні та метапластичні.

2). За типом кровотворення:

1) нормобластичні;

2) мегалобластичні.

3). За колірним показником, найважливішим диференційно-діагностичним критерієм:

1) нормохромні, коли колірний показник дорівнює 0,82-1,05;

2) гіпохромні, якщо колірний показник менший за 0,82;

3) гіперхромні, коли колірний показник вищий за 1,05.

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

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

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

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

4). За розміром еритроцитів:

1) нормоцитарні (з нормальним середнім діаметром еритроцитів 72-80 мк);

2) мікроцитарні (середній діаметр еритроцитів нижче 7,2 мк);

3) макроцитарні (діаметр еритроцитів понад 8 мк).

До групи макроцитарних анемій входять і мегалоцитарні анемії, за яких середній діаметр еритроцитів перевищує 9,0 мкм.

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

Мікроцитарними анеміями є залізодефіцитна, порфіриндефіцитна анемії, таласемія, мікросфероцитарна хвороба Міньковського - Шоффара

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

5) За регенераторною активністю кісткового мозку, що визначається на підставі вмісту ретикулоцитів у периферичній крові, виділяють анемії:

1) регенераторні, з достатньою функцією кісткового мозку. Число ретикулоцитів у периферичній крові в межах 1,0-5,0%;

2) гіпорегенераторні, зі зниженою регенераторною функцією кісткового мозку. Кількість ретикулоцитів у периферичній крові менше 0,2%;

3) гіперрегенераторні, з підвищеною регенераторною функцією кісткового мозку. Кількість ретикулоцитів у периферичній крові перевищує 5,0 %;

4) арегенераторні, з різким пригніченням еритропоезу. Ретикулоцити у периферичній крові, як правило, не визначаються.

Мартіном Фаулером у його класичній праці "Шаблони корпоративних додатків" ( Patterns of enterprise application architecture) виділено кілька підходів до організації бізнес-логіки.

  1. Транзакційний сценарій- бізнес-логіка розбивається на процедури, кожна з яких відповідає конкретному запиту, що надходить від прошарку подання.
  2. Табличний модуль- бізнес-логіка, як і в попередньому варіанті, описується в процедурному стилі, проте маніпуляції з кожною таблицею виносяться в окремий клас, що робить код більш структурованим.
  3. Модель предметної галузі- найскладніший для реалізації підхід, проте має низку переваг при описі складної логіки. Суть у тому, що виділяються об'єкти, відповідні об'єктам предметної області. Описуються відносини між цими об'єктами, які відповідають відносинам між об'єктами реального світу. При цьому вирішення технологічних питань, таких як зберігання, безпека, управління транзакціями, як правило, виноситься за межі шару бізнес-логіки.

    Виділяють два варіанти цього підходу:

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

Шаблон Модель предметної області

Перш ніж міркувати про переваги та недоліки того чи іншого варіанту, необхідно поглянути на шаблон загалом. Як було сказано вище, суть даного патерну в тому, що створюється мережа пов'язаних об'єктів, кожен з яких є модель одного об'єкта реального світу. При цьому це рішення має ряд переваг, що спрощують реалізацію складної логіки: програмісту доступні всі принципи парадигми ОВП, такі як інкапсуляція, успадкування та поліморфізм. У цьому структура класів відбиває структуру реального світу, що полегшує взаємодію по лінії " програміст - аналітик " . Люди в команді можуть спілкуватися однією мовою. Для реалізації моделі можна використовувати добре знайомі шаблони проектування. Так само даний патерн дозволяє реалізувати прозору для шару бізнес-логіки взаємодію з сховищем даних - об'єкти, що моделюють предметну область, нічого не знають про те, що насправді вони зберігаються, наприклад, у базі даних.

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

На жаль, за будь-яку перевагу слід платити. У цьому випадку плата полягає у наступному. По-перше, підвищуються вимоги до кваліфікації розробників, які проектують, реалізують і підтримують модель предметної області: необхідно вміти будувати складніші абстракції, ніж при застосуванні інших рішень. По-друге, підвищуються вимоги до використовуваних технологій. Зокрема, потрібно мати досить потужний шар доступу до даних, який реалізовував би об'єктно-реляційне відображення. Реалізація шаблону Модель предметної області зазвичай вимагає застосування потужного ORM-фреймворку, такого як Hibernate, TopLink, EclipseLinkабо OpenJPA, Що з одного боку вимагає розробників вищої кваліфікації, а з іншого - знижує продуктивність системи, що розробляється і підвищує її крихкість: будь-яким необережним дією, наприклад зміною одного рядка в описі об'єктно-реляційного відображення можна .

Анатомія насиченої та анемічної моделей

Чим анатомічно відрізняються два підходи до побудови моделі предметної галузі: насичений та анемічний? При інтенсивному підході бізнес-логіка, тобто. поведінка системи реалізується всередині об'єктів предметної галузі. Цей підхід не виключає винесення частини поведінки у службові класи, такі як *Service, *Manager, *HelperАле це виправдано тільки, коли логіка зачіпає кілька доменних об'єктів і не зрозуміло до якого саме вона відноситься. Прикладом може бути наступна невелика частина моделі предметної області Телеком. Користувачеві потрібно підключити послугу. Послуга додається у межах замовлення. При цьому необхідно перевірити, чи є організація-провайдер, яка може надати послугу із заданим набором параметрів. У разі насиченої доменної моделі логіка додавання послуги інкапсулюється у методі addNewService(Service service)класу ServiceOrder:

private List < Service>services;

private void addService(Service service) (

if (services == null )

Services = New ArrayList< Service> () ;

Services.add (service);

public void addNewService(Service service) throws NotFoundValidProviderException (

ServiceProviderRepository providerRepo = ...;

if (providerRepo.hasAvailableProvider(service.getProp1() , service.getProp2() , ...) ) (

AddService(service);

else (

throw new NotFoundValidProviderException(service) ;


Анемічна модель предметної області влаштована інакше. Класи об'єктів предметної області позбавлені поведінки. Вони мають лише конструктори та методи доступу до даних. Єдине, що вони реалізують – це стосунки з іншими об'єктами. Вся поведінка системи виноситься у шар сервісів, реалізований поверх шару моделі предметної області. Продемонструємо цей підхід на тому ж прикладі, проте тепер клас ServiceOrderматиме лише методи, які здійснюють доступ до даних. Визначення того, чи є відповідний провайдер послуги та її додавання на замовлення буде здійснюватися в ServiceOrderManager(Погодьтеся, що ServiceOrderServiceзвучить якось дивно):

public class ServiceOrder (

private List < Service>services;

public List < Service>getServices() (

return services;

public void setServices( List < Service>services) (

this .services = services;


return providerRepo;

if (order.getServices () == null )

Order.setServices (new ArrayList< Services> () ) ;

Order.getServices () .add (service);

else (

Критика Анемічної моделі предметної галузі

У спільноті розробників поширені дві основні міркування проти застосування шаблону Анемічна модель предметної області:
  • При використанні анемічної моделі предметної галузі ми відхиляємось від принципів ОВП. Суть даного критичного зауваження зводиться до того що, т.к. об'єкти предметної області у разі анемічної доменної моделі немає поведінки, ми вступаємо у суперечність із базової ідеєю ООП - мати дані та методи їх обробки одному місці.
  • При виродженні моделі предметної області в анемічній, втрачаються всі переваги, які дає даний шаблон, при цьому зберігаються його недоліки. Зокрема, застосування даного шаблону, як і раніше, вимагає досить потужного шару доступу до даних, реалізованого, наприклад, з використанням громіздких ORM-фреймворків.
Давайте розглянемо дані міркування докладніше. Анемічна модель предметної галузі суперечить принципам ОВП. У сенсі це міркування справедливо, т.к. об'єкти предметної області немає поведінки. Однак доступ до внутрішнього стану об'єктів можна інкапсулювати методами даного об'єкта. Продемонструємо цю ідею на нашому прикладі з додаванням сервісу до замовлення: до класу ServiceOrderдодається метод addService(), при цьому метод setServices()робимо приватним:

public class ServiceOrder (

private List < Service>services;

public List < Service>getServices() (

return services;

private void setServices( List < Service>services) (

this .services = services;

public void addService(Service service) (

if (services == null )

Services = New ArrayList< Service> () ;

Services.add (service);


Клас ServiceOrderManagerImplбуде здійснювати перевірку можливості додавання замовлення та викликати метод addService()класу ServiceOrder:

public class ServiceOrderManagerImpl implements ServiceOrderManager (

private ServiceProviderRepository providerRepo;

public ServiceProviderRepository getProviderRepo() (

return providerRepo;

public void setProviderRepo(ServiceProviderRepository providerRepo) (

this .providerRepo = providerRepo;

public void addNewService(ServiceOrder order, Service service) throws ProviderNotFoundException (

if (providerRepo.hasAvailableProvider(service.getParam1() , service.getParam2() , ...) ) (

Order.addService (service);

else (

throw new ProviderNotFoundException(service) ;


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

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

Інші принципи ООП, такі як спадкування та поліморфізм, залишаються доступними і при використанні анемічної моделі предметної галузі. Більшість сучасних ORM-Фреймворк допускають відображення ієрархії класів на базу даних. Наприклад, при побудові моделі фінансового застосування слід врахувати різні стратегії розрахунку ліміту овердрафту. Припустимо, є дві стратегії: немає овердрафту і є овердрафт з обмеженим лімітом. Збудуємо наступну ієрархію класів:




При цьому об'єкт класу Account- рахунок - матиме посилання на конкретну реалізацію стратегії розрахунку овердрафту, що застосовується для цього рахунку:

public class Account (

private OverdraftLimitStrategy overdraftLimitStrategy;

public OverdraftLimitStrategy getOverdraftLimitStrategy() (

return overdraftLimitStrategy;


У деякому AccountServiceми тепер можемо використати поліморфну ​​реалізацію стратегії розрахунку овердрафту:

public class AccountService (

public void withdraw(Account account, Double amount) (

if (account.getAmount() + account.getOverdraftLimitStrategy() .getLimit() > = amount) (

Account.setAmount (account.getAmount() - amount) ;


Втрачаються всі переваги, які дає шаблон Модель предметної області. Як ми розглянули вище, переваги, які дає моделювання системи в стилі ООП при використанні анемічної моделі предметної області нам як і раніше доступні. Можливо, що отримати дані переваги можна тільки при грамотному опрацюванні архітектури системи, зокрема інтерфейсів між шарами, але це відповідна плата за простішу модель. Здатність об'єктів прозоро зберігатися в довгостроковій пам'яті так само не втрачається. Як раніше об'єкт зберігався відповідною командою у репозиторії ( Repository) або ділянці роботи ( Unit of Work), так і продовжує збережуться. Синхронізація змін внутрішнього стану об'єкта зі сховищем даних залежить від цього, як саме виконується цю зміну - методом усередині класу об'єкта чи методом сервісу.

Причини популярності шаблону Анемічна модель предметної області

Тепер спробуємо знайти відповідь на питання, чому шаблон Анемічна модель предметної області такий популярний. На мій погляд, основна причина полягає в тому, що цей шаблон легше реалізується за допомогою сучасних технологій, порівняно з насиченою моделлю. Найбільш поширеним способом структурування вихідного коду є шаблон Впровадження залежностей. При цьому у додатку чітко простежується два джерела об'єктів:
  • IoC-контейнер, який реалізує шаблон Ін'єкція залежностей та будує службові об'єкти: репозиторії, послуги, фасади;
  • ORM-фрейморк, що створює об'єкти предметної області
При реалізації шаблону насиченої моделі предметної області виникає проблема зв'язування об'єктів, побудованих цими двома способами, в єдиний граф. Якщо повернутись наприклад насиченої моделі предметної області, описаному вище, то видно, що в об'єкт класу ServiceOrderпотрібно якимось чином передати об'єкт класу, що реалізує інтерфейс ServiceProviderRepository. Не всі ORM-фреймворки дозволяють ін'єктувати в об'єкти при їх побудові сторонні залежності, що реалізуються IoC-Контейнером. Доводиться використовувати підходи, які мають ряд недоліків.
  • Ін'єкція за допомогою статичних змінних та методів. Репозиторії та інші IoC-Об'єкти передаються як одинаки. Недоліки такого підходу: складніше підмінити об'єкт, наприклад, замінивши його на заглушку під час тестування. Також цей підхід вносить приховані залежності.
  • Передача залежностей через метод (не плутати з ін'єкцією через сетер). Якщо ми включаємо в об'єкт предметної області метод, що містить бізнес-логіку, то даний метод потрібно передавати всі необхідні йому об'єкти: репозиторії, фабрики, з'єднання і т.д. Недоліки такого підходу: ускладнюється сигнатура методів бізнес-логіки, всі залежності виставляються назовні, при ускладненні логіки методу, йому можуть знадобитися нові залежності, що призведе до зміни сигнатури методу та необхідності як виправляти виклик методу скрізь, де він використовується, так і якось передавати нові залежності до точок виклику.
  • Використовувати шаблон Локатор сервісів і передавати якимось чином реалізацію цього шаблону метод об'єкта предметної області. Недоліками цього є всі недоліки шаблону Локатор сервісів.
  • Замість залежностей передавати у метод результат їхньої роботи. Але цей підхід прибирає логіку з об'єкта предметної області і є першим кроком до анемічної моделі.

Переваги шаблону Анемічна модель предметної області

Крім популярності, викликаної наявною інфраструктурою, шаблон Анемічна модель предметної області має й низку власних переваг. Давайте розглянемо їх докладніше.
  1. Простота проектування та розробки. Як правило, Анемічна модель предметної області вимагає менше зусиль і кваліфікації для своєї розробки. Так як об'єкти предметної області позбавлені поведінки, що і капсулюється в сервісах, то знімається питання в який об'єкт предметної області помістити той чи інший метод. Звичайно, натомість з'являються питання в який сервіс його помістити, створювати новий сервіс чи ні, але ці питання простіше для вирішення.
  2. Простота генерації на основі сховища даних: базі даних, WSDL-опис сервісу, файлу налаштування об'єктно-реляційного відображення і т.д. Ця перевага особливо яскраво проявляється тоді, коли ми будуємо інтерфейс до успадкованої системи, реалізованої не на ООП-мові або виставляє інтерфейс у стилі віддаленого виклику процедур. При сучасному націленості інформаційних систем використання сервісно-орієнтованої архітектури дана особливість підходу грає дедалі більшу роль. Це, до речі, відрізняє поточний стан речей від часів написання критичної статті Фаулера, зрештою, минуло майже 10 років. Мені як розробнику клієнта до існуючої служби підприємства набагато простіше згенерувати модель даних щодо її - служби - контракту (наприклад, WSDL-опису) і розробити шар класів-менеджерів над даною моделлю, ніж будувати насичену модель предметної області та реалізовувати її інтеграцію з віддаленою службою.
  3. Простота повторного використання. Якщо ми маємо додаток, побудований на основі шаблону Анемічна модель предметної області і нам потрібно реалізувати додаток, що працює з тими самими даними, але реалізує іншу бізнес-логіку, ми можемо перевикористовувати класи існуючої моделі. Що стосується насиченої моделі предметної області таке перевикористання буде утруднено, т.к. бізнес-логіка жорстко зашита у класи, що реалізують модель предметної галузі. З цієї точки зору надмірна інкапсуляція швидше шкідлива, ніж корисна.

Висновок

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

Останні матеріали розділу:

Дати та події великої вітчизняної війни
Дати та події великої вітчизняної війни

О 4-й годині ранку 22 червня 1941 року війська фашистської Німеччини (5,5 млн осіб) перейшли кордони Радянського Союзу, німецькі літаки (5 тис) почали...

Все, що ви повинні знати про радіацію Джерела радіації та одиниці її виміру
Все, що ви повинні знати про радіацію Джерела радіації та одиниці її виміру

5. Дози випромінювання та одиниці виміру Дія іонізуючих випромінювань є складним процесом. Ефект опромінення залежить від величини...

Мізантропія, або Що робити, якщо я ненавиджу людей?
Мізантропія, або Що робити, якщо я ненавиджу людей?

Шкідливі поради: Як стати мізантропом і всіх радісно ненавидіти Ті, хто запевняє, що людей треба любити незалежно від обставин або...