DAO與repository模式

    1.概述

    通常,Repository和DAO的實現被認為是可互換的,尤其是在以數據為中心的應用程序中。這引起了他們之間差異的困惑。

    在本文中,我們將討論DAO和repository模式之間的區別。

    2. DAO模式

    數據訪問對像模式(也稱為DAO模式是數據持久性的抽象,被認為更接近於以表為中心的基礎存儲

    因此,在許多情況下,我們的DAO與數據庫表匹配,從而提供了一種更直接的方式來從存儲發送/檢索數據,從而隱藏了難看的查詢。

    讓我們研究一下DAO模式的簡單實現。

    2.1。 User

    首先,讓我們創建一個基本的User域類:

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

    2.2。 UserDao

    然後,我們將創建UserDao接口,該接口為User域提供簡單的CRUD操作:

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

    2.3。 UserDaoImpl

    最後,我們將創建實現UserDao接口的UserDaoImpl類:

    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.Repository模式

    根據Eric Evans的《 Domain-Driven Design 》一書“Repository是一種封裝存儲,檢索和搜索行為的機制,它模仿對象的集合。”

    同樣,根據Patterns of Enterprise Application Architecture它使用類似集合的接口訪問域對象,在域和數據映射層之間進行中介”

    換句話說,repository還處理數據並隱藏類似於DAO的查詢。但是,它處於更高的層次,更接近應用程序的業務邏輯。

    因此,repository 可以使用DAO從數據庫中獲取數據並填充域對象。或者,它可以從域對象準備數據,然後使用DAO將其發送到存儲系統以實現持久性。

    讓我們檢查一下User域的Repository模式的簡單實現。

    3.1。 UserRepository

    首先,讓我們創建UserRepository接口:

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

    在這裡,我們添加了一些通用方法,例如getaddupdateremove以處理對象集合。

    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類是貧血領域。而且,repository只是數據訪問層(DAO)之上的另一層。

    但是,DAO似乎是訪問數據的理想選擇,而repository是實現業務用例的理想方式

    4.具有多個DAO的存儲庫模式

    為了清楚地理解最後一條語句,讓我們增強User域以處理業務用例。

    想像一下,我們想通過匯總用戶的Twitter推文,Facebook帖子等來準備用戶的社交媒體資料。

    4.1。 Tweet

    首先,我們將創建Tweet類,其中包含一些用於保存tweet信息的屬性:

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

    4.2。 TweetDaoTweetDaoImpl

    然後,類似於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;
    
     }
    
     }

    在這裡,我們將調用Twitter API,以使用戶使用其電子郵件獲取所有推文。

    因此,在這種情況下,DAO使用第三方API提供了一種數據訪問機制。

    4.3。增強User

    最後,讓我們創建User類的UserSocialMedia子類,以保留Tweet對象的列表:

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

    在這裡,我們的UserSocialMedia類是一個複雜域,也包含User域的屬性。

    4.4。 UserRepositoryImpl

    現在,我們將升級UserRepositoryImpl類,以提供一個User域對像以及一條推文列表:

    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類的域對象,該類對UserSocialMedia對於我們的業務用例非常方便。因此,repository依賴於DAO來訪問來自各種來源的數據

    同樣,我們可以增強我們的User域,以保留Facebook帖子列表。

    5.比較兩種模式

    現在,我們已經了解了DAO和repository模式的細微差別,讓我們總結一下它們的區別:

    • DAO是數據持久性的抽象。但是,repository是對象集合的抽象
    • DAO是一個較低層的概念,更接近於存儲系統。但是repository是一個更高級的概念,更接近於域對象
    • DAO充當數據映射/訪問層,隱藏了難看的查詢。但是,repository是域和數據訪問層之間的一層,隱藏了整理數據和準備域對象的複雜性
    • DAO不能使用存儲庫來實現。但是,repository可以使用DAO訪問基礎存儲

    另外,如果我們有一個貧血域,則repository將只是DAO。

    此外,repository模式鼓勵域驅動的設計,也使非技術團隊成員也容易理解數據結構

    六,結論

    在本文中,我們探討了DAO和repository模式之間的差異。

    首先,我們研究了DAO模式的基本實現。然後,我們看到了使用存儲庫模式的類似實現。

    最後,我們研究了使用多個DAO的存儲庫,該存儲庫增強了域解決業務用例的能力。

    因此,我們可以得出結論,當應用程序從以數據為中心轉向面向業務時,存儲庫模式證明是一種更好的方法。

    像往常一樣,所有代碼實現都可以在GitHub上獲得