Трудно найти лучшие практики для чего-то столь же «гибкого» или абстрактного, как DTO. По сути, 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 очень поможет при его разработке.