2012-03-31 217 views
12

因此,讓我們說我們有一些實體,我們想要使用DAO對象持久化。因此,我們實施正確的接口,這樣我們結束了DAO設計模式

class JdbcUserDao implements UserDao{ 
//... 
} 

class JdbcAddressDao implements AddressDao{ 
//... 
} 

所以,如果我希望能夠從JDBC切換持久化實現以JPA(例如),反之亦然,我需要有JPAUserDao和JPAAddressDao ...如果我有20個實體,並決定切換實現(使用DI容器),那麼我必須用代碼中的JPA切換每個Jdbc實現。

現在它可能是我誤會了DAO是如何工作的,但是......如果我只是

class JdbcDaoImpl implements UserDao,AddressDao{ 
//... 
} 

我會再有所有的JDBC實現在一類,和開關實現將是一塊的蛋糕。此外,DaoImpl計數等於Dao接口的數量。爲什麼不通過實現(jdbc,JTA,JPA ...)對它們進行分組並將所有內容都放在一個類中?

在此先感謝。

+3

同樣的原因,你不編寫你的應用程序到一個大的'主()'方法:分離關注。 (順便提一句,沒有人會阻止你編寫一個包含公共代碼的抽象'JdbcDaoBase'並將其擴展到你的'Dao') – rsp 2012-03-31 09:59:51

+0

爲什麼要更換一個類中的500個方法比100個類更容易? – 2014-02-01 16:09:13

回答

20

讓單個類實現整個應用程序中的每個DAO接口將是一個相當糟糕的設計。

一個更典型的模式是有一個BaseDAO接口(也常被稱爲GenericDAO),並有一個JPABaseDAOJDBCBaseDAO等,這些基類將包含類似發現/獲得/讀取,保存/存儲/堅持,更新/修改方法並刪除/刪除/清除。

UserDAO這樣的具體DAO接口繼承自BaseDAO,具體實現如JPAUserDAOJPABaseDAO延伸。

一個BaseDAO界面看起來是這樣的:

public interface BaseDAO <T> {  
    T getByID(Long ID); 
    T save(T type); 
    T update(T type); 
    void delete(T type); 
} 

並有UserDAO接口:

@Stateless 
public class JPABaseDAO<T> implements BaseDAO<T> { 

    @PersistenceContext 
    private EntityManager entityManager; 

    private final Class<T> entityType; 

    @SuppressWarnings("unchecked") 
    public JPABaseDAO() { 
     this.entityType = ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]); 
    } 

    @Override 
    public T getByID(Long ID) { 
     return entityManager.find(entityType, ID); 
    } 

    @Override 
    public T save(T type) { 
     return entityManager.persist(type);   
    } 

    @Override 
    public T update(T type) {   
     return entityManager.merge(type); 
    } 

    @Override 
    public void delete(T type) { 
     entityManager.remove(entityManager.contains(type) ? type : entityManager.merge(type)); 
    } 

} 

和一些:實現此接口一個JPABaseDAO

public interface UserDAO extends BaseDAO<User> { 
    List<User> getAllAuthorized(); 
} 

裸露的骨頭例如樣本UserDAO實施將繼承它:

@Stateless 
public class JPAUserDAO extends JPABaseDAO<User> implements UserDAO { 

    @PersistenceContext 
    private EntityManager entityManager; 

    @Override 
    public List<User> getAllAuthorized() { 
     return entityManager.createNamedQuery("User.getAllAuthorized", User.class) 
          .getResultList(); 
    } 
} 

在實踐中,基礎類可以經常做一些其他的事情透明的,因爲如果一個實體實現某種Auditable接口的實例檢查,並自動設置,修改它的日期和用戶等

當使用EJB來實現您的DAO時,改變實現的一個策略是將所有JDBC實現放在一個包中,並將所有JPA實現放在另一個包中。然後在你的構建中只包含一個實現包。

+0

非常好,非常感謝。涉及多個表格的CRUD操作如何?例如,我會執行select語句來獲取對象並使用它來調用另一個DAO impl的CRUD,或者可能創建某種外來混合DAO?順便說一句。你對我很有幫助,非常感謝。 – Mercurial 2012-03-31 12:00:35

+1

CRUD或涉及多個實體/表的任何操作通常由聚合多個DAO的服務處理。在EJB中,即使調用多個DAO(傳播),它也會自動處於相同的持久化上下文中。另一種可能性是,如果實體相關聯(User has-a House),則只需要用戶使用DAO,JPA將從您的User對象中自動獲取/保存/更新房屋。 – 2012-03-31 12:45:23

+1

好的。這種方法是我在各種項目中遵循的方法。事實證明,它工作得很好,穩定。我在這裏詳細描述它:http://codeblock.engio.net/?p=180 – bennidi 2014-02-01 16:08:56

1

依賴注入的關鍵在於使實現之間的切換更容易,並使用戶與提供者分離。因此,所有的DI框架都提供了一些「分組」幾種實現方式(這裏是您的JDBC組和JPA組),並將它們切換到一個地方。

此外:通常消費者的數量(就您的情況而言:某些業務邏輯在用戶和地址上工作)通常高於DAO的數量,DI框架無論如何都會將大部分內容解耦。假設:每個接口有50個業務bean,兩個接口和兩個實現(總共4個):即使基本的DI也會照顧到50個。使用分組會將剩餘的一半減半。

+0

你能解釋一下「另外」部分嗎?非常感謝。 – Mercurial 2012-03-31 12:01:58

+0

@ user1304844:我想但我不知道什麼不清楚。 – 2012-03-31 12:11:12

+0

「即使是基本的DI也會照顧到50.使用分組會將剩下的一半減半。」 - 我不明白這一點。 – Mercurial 2012-03-31 12:19:37

0

絕對有可能以廣泛的技術不可知的方式實現DAO模式,以便切換持久性技術或混合多種技術變得可行。本文提供了一個在github上包含源代碼的實現方案。

http://codeblock.engio.net/?p=180