DAO so với các mẫu kho lưu trữ

1. Khái quát chung

Thông thường, việc triển khai kho lưu trữ và DAO được coi là có thể hoán đổi cho nhau, đặc biệt là trong các ứng dụng tập trung vào dữ liệu. Điều này tạo ra sự nhầm lẫn về sự khác biệt của chúng.

Trong bài viết này, chúng ta sẽ thảo luận về sự khác biệt giữa các mẫu DAO và Repository.

2. Mẫu DAO

Mẫu đối tượng truy cập dữ liệu, hay còn gọi là mẫu DAO , là một dạng trừu tượng của tính bền vững của dữ liệu và được coi là gần với bộ nhớ cơ bản hơn, thường tập trung vào bảng .

Do đó, trong nhiều trường hợp, các DAO của chúng tôi khớp với các bảng cơ sở dữ liệu, cho phép gửi / lấy dữ liệu từ bộ nhớ một cách đơn giản hơn, che giấu các truy vấn xấu xí.

Hãy xem xét một cách triển khai đơn giản của mẫu DAO.

2.1. Người dùng

Đầu tiên, hãy tạo một lớp miền Người dùng cơ bản :

public class User { private Long id; private String userName; private String firstName; private String email; // getters and setters }

2.2. UserDao

Sau đó, chúng tôi sẽ tạo giao diện UserDao cung cấp các hoạt động CRUD đơn giản cho miền Người dùng :

public interface UserDao { void create(User user); User read(Long id); void update(User user); void delete(String userName); }

2.3. UserDaoImpl

Cuối cùng, chúng ta sẽ tạo lớp UserDaoImpl triển khai giao diện 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); } // ... }

Ở đây, để đơn giản, chúng tôi đã sử dụng giao diện JPA EntityManager để tương tác với bộ nhớ cơ bản và cung cấp cơ chế truy cập dữ liệu cho miền Người dùng .

3. Mẫu kho lưu trữ

Theo cuốn sách Thiết kế theo hướng miền của Eric Evans , “kho lưu trữ là một cơ chế để đóng gói hành vi lưu trữ, truy xuất và tìm kiếm, mô phỏng một tập hợp các đối tượng.”

Tương tự như vậy, theo Mẫu Kiến trúc Ứng dụng Doanh nghiệp , nó “làm trung gian giữa miền và các lớp ánh xạ dữ liệu bằng cách sử dụng giao diện giống như bộ sưu tập để truy cập các đối tượng miền”.

Nói cách khác, một kho lưu trữ cũng xử lý dữ liệu và ẩn các truy vấn tương tự như DAO. Tuy nhiên, nó nằm ở cấp độ cao hơn, gần với logic kinh doanh của một ứng dụng.

Do đó, một kho lưu trữ có thể sử dụng DAO để tìm nạp dữ liệu từ cơ sở dữ liệu và điền vào một đối tượng miền. Hoặc, nó có thể chuẩn bị dữ liệu từ một đối tượng miền và gửi dữ liệu đó đến hệ thống lưu trữ bằng cách sử dụng DAO để duy trì lâu dài.

Hãy kiểm tra một cách triển khai đơn giản của mẫu Kho lưu trữ cho miền Người dùng .

3.1. UserRepository

Đầu tiên, hãy tạo giao diện UserRepository :

public interface UserRepository { User get(Long id); void add(User user); void update(User user); void remove(User user); }

Ở đây, chúng tôi đã thêm một số phương thức phổ biến như get , add , updateremove để làm việc với bộ sưu tập các đối tượng.

3.2. UserRepositoryImpl

Sau đó, chúng tôi sẽ tạo lớp UserRepositoryImpl cung cấp việc triển khai giao diện 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); } // ... }

Ở đây, chúng tôi đã sử dụng UserDaoImpl để gửi / lấy dữ liệu từ cơ sở dữ liệu.

Cho đến nay, chúng ta có thể nói rằng việc triển khai DAO và kho lưu trữ trông rất giống nhau vì lớp Người dùng là một miền thiếu máu. Và, một kho lưu trữ chỉ là một lớp khác trên lớp truy cập dữ liệu (DAO).

Tuy nhiên, DAO có vẻ là một ứng cử viên hoàn hảo để truy cập dữ liệu và một kho lưu trữ là một cách lý tưởng để triển khai một trường hợp sử dụng kinh doanh .

4. Mô hình kho lưu trữ với nhiều DAO

Để hiểu rõ tuyên bố cuối cùng, hãy nâng cao miền Người dùng của chúng tôi để xử lý một trường hợp sử dụng kinh doanh.

Hãy tưởng tượng chúng ta muốn chuẩn bị một hồ sơ mạng xã hội của một người dùng bằng cách tổng hợp các bài đăng trên Twitter, bài đăng trên Facebook, v.v.

4.1. tiếng riu ríu

Đầu tiên, chúng ta sẽ tạo lớp Tweet với một số thuộc tính chứa thông tin tweet:

public class Tweet { private String email; private String tweetText; private Date dateCreated; // getters and setters }

4.2. TweetDao and TweetDaoImpl

Then, similar to the UserDao, we'll create the TweetDao interface that allows fetching tweets:

public interface TweetDao { List fetchTweets(String email); }

Likewise, we'll create the TweetDaoImpl class that provides the implementation of the fetchTweets method:

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

Here, we'll call Twitter APIs to fetch all tweets by a user using his email.

So, in this case, a DAO provides a data access mechanism using third-party APIs.

4.3. Enhance User Domain

Last, let's create the UserSocialMedia subclass of our User class to keep a list of the Tweet objects:

public class UserSocialMedia extends User { private List tweets; // getters and setters }

Here, our UserSocialMedia class is a complex domain containing the properties of the User domain too.

4.4. UserRepositoryImpl

Now, we'll upgrade our UserRepositoryImpl class to provide a User domain object along with a list of tweets:

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; } }

Here, the UserRepositoryImpl extracts user data using the UserDaoImpl and user's tweets using the TweetDaoImpl.

Then, it aggregates both sets of information and provides a domain object of the UserSocialMedia class that is handy for our business use-case. Therefore, a repository relies on DAOs for accessing data from various sources.

Similarly, we can enhance our User domain to keep a list of Facebook posts.

5. Comparing the Two Patterns

Now that we've seen the nuances of the DAO and Repository patterns, let's summarize their differences:

  • DAO is an abstraction of data persistence. However, a repository is an abstraction of a collection of objects
  • DAO is a lower-level concept, closer to the storage systems. However, Repository is a higher-level concept, closer to the Domain objects
  • DAO works as a data mapping/access layer, hiding ugly queries. However, a repository is a layer between domains and data access layers, hiding the complexity of collating data and preparing a domain object
  • DAO can't be implemented using a repository. However, a repository can use a DAO for accessing underlying storage

Also, if we have an anemic domain, the repository will be just a DAO.

Additionally, the repository pattern encourages a domain-driven design, providing an easy understanding of the data structure for non-technical team members, too.

6. Conclusion

In this article, we explored differences between DAO and Repository patterns.

First, we examined a basic implementation of the DAO pattern. Then, we saw a similar implementation using the Repository pattern.

Last, we looked at a Repository utilizing multiple DAOs, enhancing the capabilities of a domain to solve a business use-case.

Therefore, we can conclude that the Repository pattern proves a better approach when an app moves from being data-centric to business-oriented.

As usual, all the code implementations are available over on GitHub.