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);
}
在這裡,我們添加了一些通用方法,例如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
類是貧血領域。而且,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。 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;
}
}
在這裡,我們將調用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上獲得。