仓储设计模式 - 每个 Dao 是否应该有一个仓储?

6
我在我的应用程序中有几个DAO,用于访问数据库进行CRUD操作。假设有新闻、天气和体育DAO。所以我对需要多少个Repositories感到困惑。我应该只使用一个Repository,比如DataRepository,并让它保存我的数据库和所有DAO,封装CRUD操作的方法吗?还是每个DAO都应该有自己的Repository?
我的意思是,Repository应该仅返回调用层理解的数据对象。因此,它就像是对DAO的封装,但我不确定是否应该为每个DAO创建一个Repository,还是只有一个Repo每个应用程序等。
如果您阅读了这篇文章article,我们开始了解该模式是过度设计或过度抽象的。它已经变成隐藏细节而不是最小化查询语句。
但似乎每个DAO都应该有一个Repo,因为接口本身看起来像这样:
interface Repository<T> {
void add(T item);
void remove(Specification specification);
List<T> query(Specification specification);

}

T可以是DAO访问的数据类型/表。现在只需要澄清一下。你能想象我有30种不同的类型,那么我就需要30个不同的Repo实现。这太荒谬了。看起来仓库模式本身就像DAO,没有区别。我很困惑。


将一个带有持久化上下文的通用抽象类创建,并将其扩展到所有子接口中,以便在应用程序中只有一个实体管理器。在像SomeDAO这样的子接口中创建您独特的方法,并根据需要使用它们。 - bananas
你能给我展示一个例子吗? - j2emanue
好的,让我来创建一个。 - bananas
1个回答

5
我不确定这是否是你想要的全部内容,但在我的应用程序中,我使用了基于Spring的DAO模式。

所以我对需要多少个仓库感到困惑。

我的看法是,你至少需要为每个实体创建一个仓库,因为它们可以导致简单的设计,但由于你正在将它们设置为通用的且位于层次结构的顶部,所以可以在子类/接口中简单地使用。
以下是示例:
定义所有基本方法以通用使用的接口。
public interface GenericDAO<T, ID extends Serializable> {


    T findById(ID id, LockModeType lock);

    void save(T entity);

    T update(T entity);

    List<T> findAll();
}

通用实现
public abstract class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID> {

    @PersistenceContext
    protected EntityManager em;

    private final Class<T> entityClass;

    public GenericDAOImpl(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    @Override
    public T findById(ID id, LockModeType lock) {
        return em.find(entityClass, id, lock);
    }

    @Override
    public void save(T entity) {
        em.persist(entity);

    }

    @Override
    public T update(T entity) {
        return em.merge(entity);
    }

    @Override
    public List<T> findAll() {
        CriteriaQuery<T> c = em.getCriteriaBuilder().createQuery(entityClass);
        c.select(c.from(entityClass));
        return em.createQuery(c).getResultList();
    }
.
.
.
}

Foo类

@Entity
public class Foo implements Serializable {

    private static final long serialVersionUID = 1L;
    private Long id;
    private String text;
}

Foo仓库

public interface FooRepositiry extends GenericDAO<Foo, Long> {

    Foo findTextById(Long id);

}

实现了Foo Repository

@Transactional
@Repository
public class FooRepoImpl extends GenericDAOImpl<Foo, Long> implements FooRepositiry {

    public FooRepoImpl() {
        super(Foo.class);
    }

    @Override
    public Foo findTextById(Long id) {
        CriteriaQuery<Foo> c = em.getCriteriaBuilder().createQuery(Foo.class);
        // .
        // .
        // .
        return em.createQuery(c).getSingleResult();
    }

}

Bar类同理

@Transactional
@Repository
public class BarRepoImpl extends GenericDAOImpl<Bar, Long> implements BarRepo {

    public BarRepoImpl() {
        super(Bar.class);
    }

    @Override
    public List<Bar> findAllBarWithText(String text) {
        CriteriaQuery<Bar> c = em.getCriteriaBuilder().createQuery(Bar.class);
        return em.createQuery(c).getResultList();
    }
}

这个通用实现需要两个东西才能工作:一个 EntityManager 和一个实体类。子类必须将实体类作为构造函数参数提供。可以使用 PersistenceContext 提供 EntityManager,也可以使用 getter-setter 方法来提供。由于 GenericDAOImpl 是抽象的,因此不能直接使用它,但是大多数常用方法都是通用的并且在层次结构中,使它们成为理想的可重用候选项。
您可以从书籍 Java Persistence with Hibernate 2nd Edition 中了解更多信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接