Рубрики
Без рубрики

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

Поймите разницу между шаблонами DAO и репозиторием на примере Java.

Автор оригинала: Anshul Bansal.

1. Обзор

Часто реализации репозитория и DAO считаются взаимозаменяемыми, особенно в приложениях, ориентированных на данные. Это создает путаницу в их различиях.

В этой статье мы обсудим различия между шаблонами DAO и репозиториями.

2. Шаблон ДАО

Шаблон объекта доступа к данным, он же DAO Pattern , является абстракцией сохранения данных и считается более близким к базовому хранилищу, которое часто ориентировано на таблицу .

Поэтому во многих случаях наши DAO соответствуют таблицам базы данных, позволяя более простой способ отправки/извлечения данных из хранилища, скрывая уродливые запросы.

Давайте рассмотрим простую реализацию шаблона DAO.

2.1. Пользователь

Во-первых, давайте создадим базовый класс User domain:

public class User {
    private Long id;
    private String userName;
    private String firstName;
    private String email;

    // getters and setters
}

2.2. UserDao

Затем мы создадим интерфейс UserDao , который обеспечивает простые операции CRUD для домена User :

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 для взаимодействия с базовым хранилищем и предоставления механизма доступа к данным для домена User .

3. Шаблон репозитория

Согласно книге Эрика Эванса Domain-Driven Design , репозиторий ” – это механизм для инкапсуляции поведения хранения, поиска и поиска, который эмулирует коллекцию объектов.”

Аналогично, в соответствии с Шаблонами архитектуры корпоративных приложений , он “посредничает между доменом и уровнями отображения данных, используя интерфейс, подобный коллекции, для доступа к объектам домена.”

Другими словами, репозиторий также имеет дело с данными и скрывает запросы, аналогичные DAO. Однако он находится на более высоком уровне, ближе к бизнес-логике приложения.

Следовательно, репозиторий может использовать DAO для извлечения данных из базы данных и заполнения объекта домена. Или он может подготовить данные из объекта домена и отправить их в систему хранения, используя DAO для сохранения.

Давайте рассмотрим простую реализацию шаблона репозитория для домена User .

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

Чтобы четко понять последнее утверждение, давайте расширим наш User домен для обработки бизнес-прецедента.

Представьте, что мы хотим подготовить профиль пользователя в социальных сетях, объединив его твиты в Twitter, сообщения в Facebook и многое другое.

4.1. Твит

Во-первых, мы создадим класс 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 fetchTweets(String email);    
}

Аналогично, мы создадим класс TweetDaoImpl , который обеспечивает реализацию метода fetchTweets :

public class TweetDaoImpl implements TweetDao {
    @Override
    public List fetchTweets(String email) {
        List tweets = new ArrayList();
        
        //call Twitter API and prepare Tweet object
        
        return tweets;
    }
}

Здесь мы вызовем API Twitter, чтобы получить все твиты пользователя, используя его электронную почту.

Таким образом, в этом случае DAO предоставляет механизм доступа к данным с использованием сторонних API.

4.3. Расширение домена Пользователя

Наконец, давайте создадим подкласс User Social Media нашего класса User , чтобы сохранить список объектов Tweet :

public class UserSocialMedia extends User {
    private List tweets;

    // getters and setters
}

Здесь наш класс User Social Media представляет собой сложный домен, содержащий свойства домена User .

4.4. UserRepositoryImpl

Теперь мы обновим наш класс UserRepositoryImpl , чтобы предоставить объект User domain вместе со списком твитов:

public class UserRepositoryImpl implements UserRepository {
    private UserDaoImpl userDaoImpl;
    private TweetDaoImpl tweetDaoImpl;
    
    @Override
    public User get(Long id) {
        UserSocialMedia user = (UserSocialMedia) userDaoImpl.read(id);
        
        List tweets = tweetDaoImpl.fetchTweets(user.getEmail());
        user.setTweets(tweets);
        
        return user;
    }
}

Здесь UserRepositoryImpl извлекает данные пользователя с помощью UserDaoImpl и твиты пользователя с помощью TweetDaoImpl.

Затем он объединяет оба набора информации и предоставляет объект домена класса User Social Media , который удобен для нашего бизнес-варианта использования. Поэтому репозиторий полагается на DAOS для доступа к данным из различных источников .

Аналогичным образом, мы можем расширить ваш Пользователь домен, чтобы сохранить список сообщений Facebook.

5. Сравнение двух моделей

Теперь, когда мы рассмотрели нюансы шаблонов DAO и репозитория, давайте обобщим их различия:

  • DAO-это абстракция сохранения данных. Однако репозиторий-это абстракция коллекции объектов
  • DAO-это концепция более низкого уровня, более близкая к системам хранения. Однако Репозиторий-это концепция более высокого уровня, более близкая к объектам домена
  • DAO работает как уровень отображения данных/доступа, скрывая уродливые запросы. Однако репозиторий-это слой между доменами и уровнями доступа к данным, скрывающий сложность сортировки данных и подготовки объекта домена
  • DAO не может быть реализован с помощью репозитория. Однако репозиторий может использовать DAO для доступа к базовому хранилищу

Кроме того, если у нас есть анемичный домен, репозиторий будет просто DAO.

Кроме того, шаблон репозитория поощряет доменный дизайн, обеспечивая легкое понимание структуры данных и для нетехнических членов команды|/.

6. Заключение

В этой статье мы исследовали различия между шаблонами DAO и репозиториями.

Во-первых, мы рассмотрели базовую реализацию шаблона DAO. Затем мы увидели аналогичную реализацию с использованием шаблона репозитория.

Наконец, мы рассмотрели репозиторий, использующий несколько DAO, расширяющий возможности домена для решения бизнес-задач.

Таким образом, мы можем сделать вывод, что шаблон репозитория доказывает лучший подход, когда приложение переходит от ориентированного на данные к бизнес-ориентированному.

Как обычно, все реализации кода доступны на GitHub .