Русские Блоги
DAO — это шаблон проектирования для доступа к базе данных.Общей идеей является инкапсуляция операций над базой данных (и таблицей данных) в класс, а другие классы вызывают методы этого класса для завершения работы базы данных. Упростите сложность и объединение классов, ответственных за бизнес-обработку
Что касается DTO, как показано
Рисунок 1: Удаленный вызов без DTO
Рисунок 2: Сокращение количества вызовов с помощью DTO
DTO это Простой набор агрегированных данных, которые необходимо передавать через процессы или границы сети. Он не должен содержать бизнес-логику и ограничивать свое поведение такими действиями, как внутренняя проверка согласованности и базовая проверка.
Основы проектирования и дизайна
Данный модуль является чисто теоретическим. Практическое задание в него не включено.
Возможно вы заметили, что приложения прошлых практик имеют схожую структуру. В этом разделе мы попытаемся объяснить, почему и для чего это сделано, попутно проанализировав их составные части.
Любое приложение работает с какими-либо данными: одни обрабатывают платежи, другие показывают доступные товары в интернет-магазине, а третьи выполняют поисковые запросы, составленные пользователем.
Во всех этих случаях у нас есть бизнес-домен — банк, интернет-магазин или поисковая система.
Бизнес-домен — набор объектов и отношений между ними, которые характеризуют какую-либо предметную область из реального мира.
Пример: Банковская система (упрощенно).
Сущности: Пользователь, организация, счет, платеж, депозит, карта.
Связи: Пользователь принадлежит организации. У пользователя может быть много счетов. Организация делает платеж другой организации. Пользователь открывает депозит. Пользователь заводит карту.
Entity
Сущности в контексте приложения обычно называются Entity.
Entity — сущность из бизнес-домена, представленная в нашей программе как класс, в котором есть только поля, геттеры и сеттеры. Никакая логика не должна содержаться в этом классе.
Пример Entity — сущность ипотечного займа.
Она используется при сохранении и получении данных из базы через слой Repository. Пример:
package ru.bank.abc.entity; /** * Ипотечный займ (упрощенный вариант) */ public class Mortgage /** * Продукт (например Семейная ипотека) */ private Product product; /** * Размер заемных средств */ private BigDecimal amount; /** * Размер ипотечной ставки */ private BigDecimal interestRate; /** * Срок кредитования */ private Integer period; /** * Список продавцов */ private ListSeller> sellers; /** * Список заявителей */ private ListApplicant> applicants; /** * Объект недвижимости */ private Realty realty; public Product getProduct() return product; > public void setProduct(Product product) this.product = product; > public BigDecimal getAmount() return amount; > //. геттеры и сеттеры для полей public Realty getRealty() return realty; > public void setRealty(Realty realty) this.realty = realty; > >
DTO
Также в приложениях выделяют сущности DTO (Data-transfer object).
Data Transfer Object (DTO) — один из шаблонов проектирования, который используется для передачи данных между подсистемами приложения.
Технически, это то же самое, что и Entity, но с точки зрения бизнес-домена, эти объекты никак не связаны с ней.
Например, несколько полей, объединенных в одну сущность (DTO) для отправки в сервис расчета графика платежей. Пример:
package ru.bank.abc.dto; /** * Запрос для расчета графика платежей */ public class PaymentScheduleCalculationRequest /** * Размер заемных средств */ private BigDecimal amount; /** * Размер ипотечной ставки */ private BigDecimal interestRate; /** * Срок кредитования */ private Integer period; public BigDecimal getAmount() return amount; > public void setAmount(BigDecimal amount) this.amount = amount; > public BigDecimal getInterestRate() return interestRate; > public void setInterestRate(BigDecimal interestRate) this.interestRate = interestRate; > public Integer getPeriod() return period; > public void setPeriod(Integer period) this.period = period; > >
Также DTO могут использоваться для слоя отображения.
То есть, это сущность, которая будет возвращаться пользователю в браузер (или в любое другое приложение-клиент) для отображения.
Как правило, нет необходимости в отображении полной сущности со всеми данными одновременно на стороне клиента. Поэтому данные возвращаются в урезанном виде, который ровно совпадает с тем, что пользователь должен увидеть в текущий момент на своем экране.
Например, если пользователь открыл форму для просмотра данных об участниках сделки, нет необходимости возвращать всю сущность ипотеки целиком, достаточно лишь вернуть DTO сущность, содержащую поля со списками продавцов List sellers и заявителей List applicants .
Service
Какие же сущности отвечают за выполнение бизнес логики в нашем приложении?
Такие классы именуются как Service (Сервис).
Service — класс, который отвечает за бизнес-логику при работе с конкретным Entity или DTO.
Как правило для каждой сущности Entity создается свой Service.
Через него может проходить логика создания\получения\обновления\удаления сущностей (CRUD операции), если такая предусмотрена в приложении.
Например для сущности Mortgage это будет MortgageService .
Он будет содержать CRUD методы, в рамках которых может выполняться дополнительная логика, например проверка корректности данных при создании нового ипотечного займа.
С уровня Service мы также можем обращаться к другим классам Service уровня.
Например при создании новой сущности Mortgage у нас возникает необходимость в расчете процентной ставки BigDecimal interestRate .
Для этого мы должны обратиться из класса MortgageService в другой класс-сервис — ExternalEvaluationService который в свою очередь сформирует специальную DTO, которую отправит (через сеть) в совершенно другое приложение, которое произведет расчет и вернет нам обратно результат через ExternalEvaluationService в MortgageService и который мы запишем в нашу сущность Mortgage в поле BigDecimal interestRate .
public interface MortgageService boolean isUserFits(User user); boolean createMortgageRequest(Mortgage mortgage); Mortgage changeRate(Mortgage old); >
Repository (DAO)
Также с уровня Service мы можем обращаться на уровень Repository (Репозиторий).
Данный слой необходим для того, чтобы сохранять в базу или получать из базы какие-либо данные.
Repository — класс, который взаимодействует с каким-либо физическим хранилищем (например База данных) для наших объектов.
Здесь опять же используется аналогичный подход — для каждой сущности Entity создается свой Repository.
Например для сущности Mortgage это будет MortgageRepository .
В чем же разница? Приведем пример из реальной жизни: мы пришли в банк и хотим положить 10 рублей на наш счет. Мы подходим к кассе и говорим операционисту наш счет, ФИО и деньги. Она пересчитывает деньги, сверяет данные и кладет деньги в кассу. С точки зрения бизнесс-домена, оператор это сервис, а касса, с которой она взаимодействует это репозиторий. Заметим следующие особенности:
- Сервис выполняет валидацию данных и, если воникла ошибка, говорит её.
- Сервис обращается к репозиторию, у которого есть свой интерфейс и внутренняя логика, скрытая от сервиса.
- Если мы захотим поменять репозиторий (способ работы с деньгами), то логика работы сервиса для конечного пользователя (нас) останется неизменной, что придает гибкости нашей программе.
- Сервис может выполнять какие-то дополнительные функции, которые нужны для нашего бизнес-процесса. Например, при успешном зачислении денег операционист выдает чек-квитанцию.

Важно понимать, что при переносе такой модели в программный код, все реалзации классов должны лежать в своих пакетах, которые соответствуют их сущности: entity , dto , service , repostory . Например:
Иногда слой хранения данных делят на 2 паттерна:
- DAO (Data Access Object)
- рассмотренный выше Repository
Они оба отвечают за взаимодействие с каким-то хранилищем сущностей. В чем же тогда заключается разница между ними?
Представим ситуацию, что мы реализуем хранение сущности User . В случае с UserRepository у нас был бы следующий интерфейс:
public interface UserRepository User get(String userName); void create(User user); void update(User user); void delete(String userName); ListUser> query(UserSpecification specification); // Один метод что правит всеми запросами поиска >
А в случае с UserDAO такой:
public interface UserDAO void create(User user); void update(User user); void delete(User user); ListUser> getUserByLastName(String lastName); User getUserByAgeRange(int minAge, int maxAge); // Еще миллион методов поиска с разными параметрами >
Наверное, вы уже уловили суть. Самое главное отличие Repository от DAO в том, что он инкапсулируют всевозможные варианты поиска сущности в какой-то объект UserSpecification. В нем могут содержаться различные комбинации полей, по которым идет поиск, сколько страниц сущностей мы хотим увидеть и в каком порядке (сортировка).

В общем случае наша программа будет выглядеть следующим образом (Разве что у нас нет базы данных):
Чистый код
Для того чтобы хорошо написать программу, недостаточно просто знать, на какие классы разделить функционал. Важно знать и понимать, как писать качественный, красивый и легкий в поддержке код.
Принцип S.O.L.I.D.
Принцип S.O.L.I.D. — это акроним из 5 основных принципов проектирования программ:
- Single Responsibility (Принцип единственной ответственности ) — Каждый класс должен иметь одну и только одну причину для изменений. С нарушением SRP система с трудом поддается изменениям, поскольку любое минимальное изменение вызывает эффект «снежного кома», затрагивающего другие компоненты системы.
- Open Closed Principle (Принцип открытости/закрытости) — Программные сущности должны быть:
- открыты для расширения(наследования)
- закрыты для изменения
Идея в том, что однажды разработанная реализация класса в дальнейшем требует только исправления ошибок, а новые или изменённые функции требуют создания нового класса. Этот новый класс может переиспользовать код исходного класса через механизм наследования. Производный подкласс может реализовывать или не реализовывать интерфейс исходного класса.
- Liskov Substitution Principle (Принцип подстановки Барбары Лисков) — объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы. Проще говоря, если у вас в проекте повсеместно используется экземпляры класса Collection , то вы вольны заменить их на List , Set или Queue .
- Interface Segregation Principle (Принцип разделения интерфейса) — много интерфейсов, специально предназначенных для клиентов, лучше, чем один интерфейс общего назначения.
- Dependency Inversion Principle (Принцип инверсии зависимостей) — Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. Сюда входя следующие кейсы:
- Все типы переменных должны быть объявлены интерфейсом или абстрактным классом.
- Все классы должны быть зависимыми только от интерфейсов других классов. ? Все инициализации переменных должны происходить через паттерн Inversion of Control — например с помощью Factory method или механизмом Dependency injection
Принцип DRY
Принцип, нацеленный на снижение повторения информации различного рода. Нацелен на уменьшение кода и упрошения связей между сущностями.
Принцип YAGNI
Принцип, при котором в качестве основной цели и/или ценности декларируется отказ от избыточной функциональности. Цель этого принципа в уменьшении количества фич, и, как следствие, количества кода, модулей и зависимостей.
Принцип KISS
Принцип, запрещающий использование более сложных решений, чем это необходимо. Он происходит от похожих концепций, таких как бритва Оккама , который гласит Не следует множить сущее без необходимости .
Основные материалы
- Видео: Learn — Clean Code
- Стиль кода Java
- Три ключевых принципа ПО, которые вы должны понимать
Дополнительные материалы
- Stackoverflow: DTO vs entity
- Stackoverflow: Repository vs service
- Habr: DAO vs Repository
- Книга: Роберт Мартин — Чистый код
Вопросы для самоконтроля
Java Program Structure
- Что такое Entity?
- Что такое DTO? Как расшифровывается?
- В чем разница между Entity и DTO?
- За что отвечает слой Service?
- За что отвечает слой Repository?
- Для чего нужно делить наше приложение на слои?
Java — Programming Principles
- Что такое принцип DRY? Как вы его понимаете?
- Что такое принцип KISS? Как вы его понимаете?
- Что такое принцип YAGNI? Как вы его понимаете?
- Что такое SOLID? Из каких составляющих принципов он состоит?
- Приведите пример нарушения принципа Liskov Substitution
- В чем основная цель приципа Dependency Inversion ?
Developed by Timur Sokolov and Ilia Isakhin.
We believe that knowledge is the most powerful tool you can use to change your life for better.
© 2019-2020 EPAM Systems, Izhevsk.
Взаимодействие базы данных с шаблонами проектирования DAO и DTO
DAO означает объект доступа к данным и является шаблоном промышленного дизайна. В этой статье я расскажу, что такое DAO и как создать DAO. Я также расскажу о значении создания объектов доступа к данным.
Существуют инструменты, которые могут генерировать код DAO для приложения. Но можно также написать классы DAO вручную. Еще один шаблон проектирования, тесно связанный с DAO, — это DTO (объект доступа к данным).
Шаблон проектирования DAO помогает приложению выполнять различные операции CRUD над базой данных. Классы DAO предоставляют методы для вставки, удаления, обновления и методов поиска. Основной целью создания DAO является слабая связь и неповторение кода.
В любом приложении, которое будет взаимодействовать с базой данных, необходимо выполнять операции CRUD над таблицами базы данных, и поскольку операции над таблицами могут выполняться разными классами, и, следовательно, повторение одного и того же кода в разных классах становится затруднительным. Более того, даже после повторения кода становится трудно поддерживать код взаимодействия с базой данных, когда требуются изменения в способе взаимодействия с базой данных.
Чтобы преодолеть вышеупомянутые проблемы, была изобретена схема проектирования DAO. Предполагается, что шаблон DAO имеет интерфейс, класс и фабрику DAO, соответствующие каждой таблице в таблице. Например, если в базе данных есть имя таблицы Employees, то должен существовать интерфейс с именем EmployeesDAO, класс с именем EmployeesDAOImpl и фабричный класс EmployeeDAOFactory.
Интерфейс EmployeesDAO должен выглядеть примерно так:
package com.company.app.dao;public interface < public Employee[] findAll() throws SQLException; public Employee findByPK(EmployeePK) throws SQL Exception; public Employee[] findbyemployeename(String EmployeeName) throws SQLException; public boolean insert(Employee employee) throws SQLException; public boolean update(Employee employee) throws SQLException; public boolean delete(Employee employee) throws SQLException;>
Класс реализации DAO выглядит так:
package com.company.aap.doaimpl;public class EmployeeDAOImpl implements EmployeeDAO < Connection con; ResultSet rs; PreparedStatement stmt; public Employee[] findAll() throws SQLException < Employee[] employees; String SQL_QUERY= “Select * from Employee”; con=ResourceManager.getConnection(); stmt = con.prepareStatement(SQL_QUERY); rs = stmt.executeQuery(); while(rs.next) < //get columns and store in array > return employees; > public Employee findByPK(EmployeePK) throws SQL Exception < //Implementation code >public Employee[] findbyemployeename(String EmployeeName) throws SQLException < //Implementation code >public boolean insert(Employee employee) throws SQLException < //Implementation code >public boolean update(Employee employee) throws SQLException < //Implementation code >public boolean delete(Employee employee) throws SQLException< //Implementation code >>
В приведенном выше коде реализации DAO класс Employee является объектом передачи данных, который имеет переменные-члены, соответствующие таблице Employee в базе данных. Таким образом, Employee — это POJO в некотором смысле с геттерами и сеттерами для переменных-членов.
Класс DAO Factory, который представляет собой EmployeeDAOFactory, используется для возврата объекта EmployeeDAOImpl. Вот код для DAO facrory для EmployeeDAO:
package com.company.app.factory;public class EmployeeDAOFactory < public static EmployeeDAO create() < return (new EmployeeDAOImpl()); >>
В EmployeeDAOImpl есть класс ResourceManager, цель которого — создать соединение с базой данных и вернуть его обратно. Таким образом, этот класс действует как вспомогательный класс для различных других классов реализации DAO.
Как я уже упоминал в начале этой статьи, есть инструменты, которые могут генерировать для вас код класса DAO, DTO и Factory. Эти инструменты полезны, потому что они автоматизируют генерацию классов DAO. Важность этих инструментов даже становится большой на начальном этапе разработки приложений, потому что схема базы данных часто сохраняет изменения и, следовательно, вручную вносит изменения в таблицы базы данных и код DAO. Здесь я перечисляю инструменты, которые могут генерировать код DAO для приложений Java:
- FireStrom DAO от Codefutures
- DaoGen от TitanicLinux.net
- Dao4J
- БД Визуал Архитектор
Эти инструменты выполняют импорт таблиц из базы данных, запрашивая сведения о соединении, а затем генерируют классы DAO / DTO на основе импортируемых таблиц. Еще один важный момент, который полезен при использовании этих инструментов, заключается в том, что они проверяют первичные и внешние ключи структуры таблицы. Кроме того, типы данных базы данных преобразуются в соответствующие типы данных в Java в классах DAO / DTO.
После того, как код был сгенерирован этими инструментами, всегда можно изменить код для оптимизации кода DAO.
Всегда помните, что DAO, DTO, Factory, Loose Coupling (принцип SOLID), шаблоны проектирования Factory все вместе. Можно также создать пул соединений при использовании шаблона проектирования DAO. Важным моментом является то, что код становится чистым и понятным при использовании шаблонов проектирования DAO, DTO.
Чем dao отличается от dto
Давайте соберем и систематизируем информацию об этих подходах к организации доступа к данным. А именно, какая между ними разница, какие преимущества и недостатки у этих паттернов и в каких случаях их применять.
Спросил safonovea
1011 дн., 22 час., 2 мин. назад
Лучший ответ:
Прежде чем ответить на все вопросы, предлагаю выяснить назначение и принципы действия каждого из паттернов.
DAO
Итак, паттерн DAO (Data Access Object) получил особо широкое распространение и применение в мире J2EE. Его прямое предназначение — абстрагировать и инкапсулировать доступ к источнику данных. DAO управляет соединением с источником данных для получения и записи данных.
В классическом варианте DAO содержит только стандартные CRUD-методы. Клиент вызывает эти методы получая или передавая в качестве аргумента так называемый DTO (Data Transfer Object).
По сути, DAO является реализацией слоя отображения реляционных данных в объекты и наоборот. Именно здесь сосредотачивается решение проблемы, известной как «Object-relational impedance mismatch».
Repository
Рассмотрим теперь паттерн Repository. Repository выступает в роли посредника между слоем домена и слоем отображения реляционных данных. Он выполняет роль коллекции объектов домена в оперативной памяти. Таким образом, репозиторий представляет собой более высокий уровень абстракции над слоем отображения данных.
Repository является ориентрованным на модель предметной области, в то время как DAO больше ориентирован на источник данных. Это означает, что Repository может содержать методы, возвращающие объекты предметной области, удовлетворящие какому-либо заданному критерию, а также содержать логику конструирования запросов к нижележащему слою (собственно DAO).
Объекты, запрашиваемые у репозитория, могут иметь довольно сложную структуру. Например, объект Employee может содержать ссылку на объект Organization. Для того, чтобы обеспечить корректную работу по сохранению и загрузке подобных объектов репозиторию может понадобиться один или несколько DAO.
Выводы
Что же мы имеем в итоге? Выходит, что вопрос о взаимоисключающем использовании паттернов Repository и DAO несколько некорректен. Эти решения можно задействовать в связке. Применяя Repository как коллекцию объектов в памяти, мы можем поместить DAO на более низкий уровень и инкапсулировать в нем логику обращения к источнику данных. Важно помнить об обязанностях каждого из решений.
Ниже приведу краткий список тезисов, характеризующих различия между Repository и DAO:
- DAO инкапсулирует доступ к источнику данных
- DAO является реализацией слоя объектно-реляционного отображения
- DAO более ориентирован на источник данных
- Repository представляет более высокий уровень абстракции
- Repository выполняет роль коллекции объектов домена в памяти
- Repository ориентирован на модель предметной области
Ответил safonovea
1008 дн., 22 час., 3 мин. назад
Правильно я понимаю, что если доступ к данным реализуется через ORM-библиотеку, то слой DAO отсутствует и создается только слой репозиториев, которые используют API ORM для получения/сохранения данных?
Тоже думал над этим вопросом. Да, наверное, так и есть. Только при использовании репозитория часто забывается про коллекцию уже загруженных объектов, а между тем, на мой взгляд это довольно важный аспект, напрямую влияющий на производительность взаимодействия приложения и БД.
Ну если используется зрелое ORM решение, типа (N)Hibernate, то о кешировании можно особенно не беспокоиться (во всяком случае на уровне репозитория).
Повторное использование знаний