2012-03-31 18 views
12

Also sagen wir, wir haben ein paar Entitäten, die wir mit DAO-Objekten persistieren wollen. So setzen wir die richtige Schnittstelle, so dass wir mitDAO Designmuster

class JdbcUserDao implements UserDao{ 
//... 
} 

class JdbcAddressDao implements AddressDao{ 
//... 
} 

am Ende Also, wenn ich von JDBC zu JPA wechseln persistance Implementierungen in der Lage sein wollen (zum Beispiel), und umgekehrt, würde ich brauchen, um JPAUserDao und JPAAddressDao ... Wenn ich 20 Entitäten hätte und entschied, Implementierungen zu wechseln (mit DI-Container), müsste ich jede Jdbc-Implementierung mit JPA in Code umstellen.

Nun könnte es sein, dass ich das falsch verstanden, wie DAO funktioniert, aber ... Wenn ich nur

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

ich dann die JDBC-Implementierungen alle in einer Klasse hatte, und Switching-Implementierungen wären ein Stück sein Kuchen. Außerdem ist DaoImpl count gleich der Anzahl der Dao-Schnittstellen. Warum gruppieren Sie sie nicht einfach nach Implementierung (jdbc, JTA, JPA ...) und haben alles unter einer Klasse?

Vielen Dank im Voraus.

+3

Aus dem gleichen Grunde, warum Sie Ihre Anwendung in einer großen 'main()' Methode nicht Code aus: Trennung von Bedenken. (Übrigens hindert Sie niemand daran, eine abstrakte 'JdbcDaoBase' zu ​​schreiben, die gemeinsamen Code enthält und diese in Ihren 'Dao's erweitert). – rsp

+0

Warum sollte es einfacher sein, 500 Methoden in einer Klasse als in 100 Klassen zu ersetzen? –

Antwort

20

Mit einer einzigen Klasse implementieren jede DAO-Schnittstelle in Ihrer gesamten Anwendung wäre ein eher schlechtes Design.

Ein typisches Muster ist eine BaseDAO Schnittstelle haben (auch oft genannt GenericDAO) und haben eine JPABaseDAO, JDBCBaseDAO usw. Diese Klassen Basis werden Methoden enthalten wie finden/get/lesen, speichern/store/anhalten, aktualisieren/ändern und löschen/entfernen/löschen.

Spezifische DAO-Schnittstellen wie UserDAO dann erben von BaseDAO und konkrete Implementierungen wie JPAUserDAO von JPABaseDAO erstreckt.

A BaseDAO Schnittstelle könnte wie folgt aussehen:

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

Und eine UserDAO Schnittstelle:

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

Bare bones Beispiel einer JPABaseDAO Umsetzung dieser Schnittstelle:

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

} 

und einige Probe UserDAO Implementierung, die von ihm erben würde:

@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(); 
    } 
} 

In der Praxis die Basisklasse oft transparent machen einige andere Dinge, für die Überprüfung Beispiel, wenn ein Unternehmen eine Art von Auditable-Schnittstelle implementiert, und das Datum und die Benutzer automatisch einstellen, dass es geändert usw.

Wenn Sie EJB zur Implementierung Ihrer DAOs verwenden, besteht eine Strategie zum Ändern von Implementierungen darin, alle JDBC-Implementierungen in ein Paket und alle JPA-Implementierungen in das andere zu integrieren. Fügen Sie dann nur ein Implementierungspaket in Ihren Build ein.

+0

Ausgezeichnet, vielen Dank. Was ist mit CRUD-Operationen mit mehreren Tabellen? Würde ich zum Beispiel eine select-Anweisung ausführen, um ein Objekt zu erhalten und damit CRUD eines anderen DAO-Impls aufzurufen, oder vielleicht eine Art Alien-Hybrid-DAO erstellen? Übrigens. Sie haben mir sehr geholfen, sehr geschätzt. – Mercurial

+1

CRUD oder was auch immer Operationen mit mehreren Entitäten/Tabellen werden oft von Services behandelt, die mehrere DAOs aggregieren. In EJB befinden Sie sich automatisch im selben Persistenzkontext, auch wenn Sie mehrere DAOs aufrufen (es propagiert). Eine andere Möglichkeit besteht darin, dass wenn Entitäten zugeordnet sind (Benutzer hat ein Haus), Sie nur ein DAO für einen Benutzer benötigen und JPA Häuser automatisch von Ihren Benutzerobjekten holen/speichern/aktualisieren wird. –

+1

Ja schön. Diese Herangehensweise habe ich in verschiedenen Projekten verfolgt. Es hat sich als recht gut und stabil erwiesen. Ich beschreibe es im Detail hier: http://codeblock.engio.net/?p=180 – bennidi

1

Der ganze Sinn von Dependency Injection ist es, den Wechsel zwischen der Implementierung zu erleichtern und den Benutzer vom Provider zu entkoppeln. Daher bieten alle DI-Frameworks eine Möglichkeit, mehrere Implementierungen (hier Ihre JDBC-Gruppe und Ihre JPA-Gruppe) zu "gruppieren" und sie an einer Stelle zu wechseln.

Auch: Normalerweise ist die Anzahl der Verbraucher (in Ihrem Fall: einige Geschäftslogik arbeitet an Benutzern und Adressen) in der Regel höher als die Anzahl der DAOs das DI-Framework wird die meisten Sachen für Sie sowieso entkoppeln. Angenommen: 50 Business-Beans, zwei Interfaces und zwei Implementierungen für jede Schnittstelle (insgesamt 4): selbst Basic DI kümmert sich um die 50. Die Gruppierung wird diese verbleibende Pause für Sie halbieren.

+0

Könnten Sie bitte den "Also" Teil erklären? Vielen Dank. – Mercurial

+0

@ user1304844: Ich würde gerne, aber ich weiß nicht, was unklar ist. –

+0

"sogar einfache DI wird sich um die 50 kümmern. Durch die Gruppierung wird diese verbleibende Pause für dich halbiert." - Ich verstehe das nicht. – Mercurial

0

Es gibt definitiv Möglichkeiten, das DAO-Muster weitestgehend technologie-agnostisch zu implementieren, so dass Switching-Persistence-Technologie oder sogar das Mischen mehrerer Technologien möglich wird. Dieser Artikel stellt ein Implementierungsschema mit Quellcode auf GitHub vor.

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