DAO设计模式

时间:2012-03-31 09:36:15

标签: java design-patterns 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 个答案:

答案 0 :(得分:20)

在整个应用程序中使用单个类实现每个DAO接口将是一个相当糟糕的设计。

更典型的模式是拥有BaseDAO接口(通常也称为GenericDAO)并拥有JPABaseDAOJDBCBaseDAO等。这些基类将包含类似的方法find / get / read,save / store / persist,update / modify and delete / remove / purge。

UserDAO等特定DAO接口继承自BaseDAOJPAUserDAO等具体实现从JPABaseDAO延伸。

BaseDAO界面可能如下所示:

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

UserDAO界面:

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

实现此接口的JPABaseDAO的裸骨示例:

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

}

以及从中继承的一些示例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实现放在另一个包中。然后只在构建中包含一个实现包。

答案 1 :(得分:1)

依赖注入的重点是使实现之间的切换更容易,并将用户与提供者分离。因此,所有DI框架都提供了一些方法来“组合”多个实现(这里是您的JDBC组和JPA组)并将它们切换到一个位置。

另外:通常消费者的数量(在您的情况下:一些处理用户和地址的业务逻辑)通常高于DI框架将为您解开大部分内容的DAO数量。假设:每个界面有50个业务bean,两个接口和两个实现(总共4个):即使是基本的DI也会照顾50个。使用分组会将剩余的剩余时间减半。

答案 2 :(得分:0)

绝对有可能以广泛的技术不可知的方式实现DAO模式,使得切换持久性技术甚至混合多种技术变得可行。本文介绍了一种实现方案,包括github上的源代码。

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