Важко встановити кращі практики для чогось такого "гнучкого" або абстрактного, як DTO. По суті, DTO - це лише об'єкти для передачі даних, але залежно від місця призначення або причини передачі, ви можете застосувати різні "найкращі практики".
Я рекомендую прочитати " Шаблони архітектури корпоративних додатків" Мартіна Фаулера . Існує ціла глава, присвячена моделям, де ДТО отримує дійсно докладний розділ.
Спочатку вони були "розроблені" для використання у дорогих віддалених дзвінках, де вам, швидше за все, знадобиться багато даних з різних частин вашої логіки; DTO здійснюватимуть передачу даних за один виклик.
За словами автора, DTO не передбачалося використовувати в місцевих середовищах, але деякі люди знайшли для них застосування. Зазвичай вони використовуються для збору інформації з різних POCO в єдине ціле для GUI, API або різних рівнів.
Тепер при успадкуванні повторне використання коду більше схоже на побічний ефект успадкування, а не на його основну мету; композиція, з іншого боку, реалізується з повторним використанням коду як основної мети.
Деякі рекомендують спільно використовувати склад і спадщину, використовуючи сильні сторони обох і намагаючись пом’якшити їх слабкі сторони. Далі є частиною мого розумового процесу при виборі або створенні нових DTO або будь-якого нового класу / об'єкта з цього приводу:
- Я використовую успадкування з DTO всередині того ж шару або того ж контексту. DTO ніколи не успадковує POCO, BLL DTO ніколи не успадковує від DAL DTO тощо.
- Якщо я виявлю, що намагаюся приховати поле від DTO, я рефактор і, можливо, використаю композицію замість цього.
- Якщо дуже мало різних полів з базового DTO - це все, що мені потрібно, я вкладу їх у загальний DTO. Універсальні DTO використовуються лише всередині.
- Базова POCO / DTO майже ніколи не буде використовуватися для будь-якої логіки, таким чином база відповідає лише потребам своїх дітей. Якщо мені коли-небудь потрібно використовувати базу, я уникаю додавати будь-яке нове поле, яке його діти ніколи не використовуватимуть.
Деякі з них можуть бути не «найкращими» методами, вони досить добре працюють над проектами, над якими я працював, але потрібно пам’ятати, що жоден розмір не підходить усім. У випадку з універсальним DTO ви повинні бути обережними, мої методи підписів виглядають так:
public void DoSomething(BaseDTO base) {
//Some code
}
Якщо будь-який з методів коли-небудь потребує власного DTO, я роблю спадщину, і зазвичай єдине зміна, яке мені потрібно внести, це параметр, хоча іноді мені потрібно копати глибше для конкретних випадків.
З ваших коментарів я розумію, що ви використовуєте вкладені DTO. Якщо ваші вкладені DTO складаються лише зі списку інших DTO, я вважаю, що найкраще зробити це розгортати список.
Залежно від кількості даних, які потрібно відобразити або працювати з ними, може бути хорошою ідеєю створити нові DTO, які обмежують дані; Наприклад, якщо ваш UserDTO має багато полів, і вам потрібно лише 1 або 2, може бути кращим мати DTO лише з цими полями. Визначення шару, контексту, використання та корисності DTO дуже допоможе при його розробці.