«1. Обзор
Часто реализации репозитория и DAO считаются взаимозаменяемыми, особенно в приложениях, ориентированных на данные. Это создает путаницу в их различиях.
В этой статье мы обсудим различия между шаблонами DAO и Repository.
2. Шаблон DAO
Шаблон объекта доступа к данным, также известный как шаблон 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 для сохранения.
Давайте рассмотрим простую реализацию шаблона репозитория для пользовательского домена.
3.1. UserRepository
Во-первых, давайте создадим интерфейс 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
Во-первых, мы создадим класс Tweet с несколькими свойствами, которые содержат информацию о твитах:
public class Tweet {
private String email;
private String tweetText;
private Date dateCreated;
// getters and setters
}
4.2. TweetDao и TweetDaoImpl
Затем, аналогично 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, расширяющий возможности домена для решения бизнес-прецедентов.
Таким образом, мы можем сделать вывод, что шаблон репозитория является лучшим подходом, когда приложение переходит от ориентированного на данные к бизнес-ориентированному.