1. Обзор
Часто реализации репозитория и DAO считаются взаимозаменяемыми, особенно в приложениях, ориентированных на данные. Это создает путаницу в их различиях.
В этой статье мы обсудим различия между шаблонами DAO и Repository.
2. Шаблон ДАО
Шаблон объекта доступа к данным, также известный как шаблон DAO , представляет собой абстракцию сохраняемости данных и считается более близким к базовому хранилищу, которое часто ориентировано на таблицы .
Поэтому во многих случаях наши DAO соответствуют таблицам базы данных, что позволяет более просто отправлять/извлекать данные из хранилища, скрывая уродливые запросы.
Давайте рассмотрим простую реализацию шаблона DAO.
2.1. Пользователь
Во-первых, давайте создадим базовый класс домена пользователя :
public class User {
private Long id;
private String userName;
private String firstName;
private String email;
// getters and setters
}
2.2. UserDao
Затем мы создадим интерфейс UserDao
, который обеспечивает простые операции CRUD для пользовательского
домена:
public interface UserDao {
void create(User user);
User read(Long id);
void update(User user);
void delete(String userName);
}
2.3. UserDaoImpl
Наконец, мы создадим класс UserDaoImpl , реализующий интерфейс
UserDao
:
public class UserDaoImpl implements UserDao {
private final EntityManager entityManager;
@Override
public void create(User user) {
entityManager.persist(user);
}
@Override
public User read(long id) {
return entityManager.find(User.class, id);
}
// ...
}
Здесь для простоты мы использовали интерфейс JPA EntityManager
для взаимодействия с базовым хранилищем и предоставления механизма доступа к данным для пользовательского
домена.
3. Шаблон репозитория
Согласно книге Эрика Эванса « Domain-Driven Design»
, «репозиторий — это механизм для инкапсуляции поведения хранения, поиска и поиска, который эмулирует набор объектов».
Точно так же, согласно Patterns of Enterprise Application Architecture
, он «является посредником между уровнями отображения домена и данных, используя интерфейс, похожий на коллекцию, для доступа к объектам домена».
Другими словами, репозиторий также имеет дело с данными и скрывает запросы, подобные DAO. Однако он находится на более высоком уровне, ближе к бизнес-логике приложения.
Следовательно, репозиторий может использовать DAO для извлечения данных из базы данных и заполнения объекта домена. Или он может подготовить данные из объекта домена и отправить их в систему хранения, используя DAO для сохранения.
Давайте рассмотрим простую реализацию шаблона репозитория для пользовательского
домена.
3.1. Пользовательский репозиторий
Во-первых, давайте создадим интерфейс UserRepository
:
public interface UserRepository {
User get(Long id);
void add(User user);
void update(User user);
void remove(User user);
}
Здесь мы добавили несколько общих методов, таких как get
, add
, update
и remove
, для работы с коллекцией объектов.
3.2. UserRepositoryImpl
Затем мы создадим класс UserRepositoryImpl
, обеспечивающий реализацию интерфейса UserRepository
: ``
public class UserRepositoryImpl implements UserRepository {
private UserDaoImpl userDaoImpl;
@Override
public User get(Long id) {
User user = userDaoImpl.read(id);
return user;
}
@Override
public void add(User user) {
userDaoImpl.create(user);
}
// ...
}
Здесь мы использовали UserDaoImpl
для отправки/получения данных из базы данных.
Пока что мы можем сказать, что реализации DAO и репозитория выглядят очень похоже, потому что класс User
— это анемичный домен. И репозиторий — это просто еще один уровень над уровнем доступа к данным (DAO).
Тем не менее, DAO кажется идеальным кандидатом для доступа к данным, а репозиторий — идеальным способом реализации бизнес-прецедента .
4. Шаблон репозитория с несколькими DAO
Чтобы четко понять последнее утверждение, давайте расширим наш домен пользователя
, чтобы он мог обрабатывать бизнес-вариант.
Представьте, что мы хотим подготовить профиль пользователя в социальной сети, объединив его твиты в Твиттере, посты в Фейсбуке и многое другое.
4.1. Твитнуть
Во-первых, мы создадим класс Tweet
с несколькими свойствами, которые содержат информацию о твите:
public class Tweet {
private String email;
private String tweetText;
private Date dateCreated;
// getters and setters
}
4.2. ТвитДао
и ТвитДаоИмпл
Затем, аналогично UserDao
, мы создадим интерфейс TweetDao
, позволяющий получать твиты:
public interface TweetDao {
List<Tweet> fetchTweets(String email);
}
Точно так же мы создадим класс TweetDaoImpl
, обеспечивающий реализацию метода fetchTweets
:
public class TweetDaoImpl implements TweetDao {
@Override
public List<Tweet> fetchTweets(String email) {
List<Tweet> tweets = new ArrayList<Tweet>();
//call Twitter API and prepare Tweet object
return tweets;
}
}
Здесь мы вызовем API Twitter, чтобы получить все твиты пользователя, использующего его электронную почту.
Итак, в этом случае DAO предоставляет механизм доступа к данным с использованием сторонних API.
4.3. Расширение пользовательского
домена
Наконец, давайте создадим подкласс UserSocialMedia
нашего класса User
, чтобы сохранить список объектов Tweet
:
public class UserSocialMedia extends User {
private List<Tweet> tweets;
// getters and setters
}
Здесь наш класс UserSocialMedia
представляет собой сложный домен, содержащий также свойства домена пользователя
.
4.4. UserRepositoryImpl
Теперь мы обновим наш класс UserRepositoryImpl
, чтобы предоставить объект домена пользователя
вместе со списком твитов: ``
public class UserRepositoryImpl implements UserRepository {
private UserDaoImpl userDaoImpl;
private TweetDaoImpl tweetDaoImpl;
@Override
public User get(Long id) {
UserSocialMedia user = (UserSocialMedia) userDaoImpl.read(id);
List<Tweet> tweets = tweetDaoImpl.fetchTweets(user.getEmail());
user.setTweets(tweets);
return user;
}
}
Здесь UserRepositoryImpl
извлекает пользовательские данные с помощью UserDaoImpl
и твиты пользователя с помощью TweetDaoImpl.
Затем он объединяет оба набора информации и предоставляет доменный объект класса UserSocialMedia
, который удобен для нашего делового варианта использования. Поэтому репозиторий использует DAO для доступа к данным из различных источников .
Точно так же мы можем улучшить наш домен пользователя
, чтобы хранить список сообщений Facebook.
5. Сравнение двух паттернов
Теперь, когда мы увидели нюансы шаблонов DAO и Repository, давайте суммируем их различия:
- DAO — это абстракция сохраняемости данных. Однако репозиторий — это абстракция набора объектов.
- DAO — это концепция более низкого уровня, более близкая к системам хранения. Однако репозиторий — это концепция более высокого уровня, более близкая к объектам домена.
- DAO работает как слой отображения/доступа к данным, скрывая уродливые запросы. Однако репозиторий — это слой между доменами и уровнями доступа к данным, скрывающий сложность сопоставления данных и подготовки объекта предметной области.
- DAO нельзя реализовать с помощью репозитория. Однако репозиторий может использовать DAO для доступа к базовому хранилищу.
Кроме того, если у нас анемичный домен, репозиторий будет просто DAO.
Кроме того, шаблон репозитория поощряет дизайн, ориентированный на предметную область, обеспечивая легкое понимание структуры данных и для нетехнических членов команды .
6. Заключение
В этой статье мы рассмотрели различия между шаблонами DAO и Repository.
Сначала мы рассмотрели базовую реализацию шаблона DAO. Затем мы увидели аналогичную реализацию с использованием шаблона Repository.
Наконец, мы рассмотрели репозиторий, использующий несколько DAO, расширяющий возможности домена для решения бизнес-прецедентов.
Таким образом, мы можем сделать вывод, что шаблон репозитория является лучшим подходом, когда приложение переходит от ориентированного на данные к бизнес-ориентированному.
Как обычно, все реализации кода доступны на GitHub .