Перейти к основному содержимому

DAO против шаблонов репозитория

· 6 мин. чтения

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 .