Dao和Repository,你还傻傻分不清吗?

发布时间 2023-10-13 15:24:55作者: 珊瑚贝博客
DAO到底有没有必要?

        贫血模型中的DAO或领域模型中的Repository到底有没有必要?有人认为DAO或者说Repository是充血模型的大敌,对此我无论如何也不赞同。DAO或Repository是负责持久化逻辑的,如果取消掉DAO或Repository,将持久化逻辑直接写入到model对象中,势必造成model对象承担不必要的职责。虽然现在的ORM框架已经做得很好了,持久化逻辑还是需要大量的代码,持久化逻辑的掺入会使model中的业务逻辑变得模糊。允许去掉DAO的一个必要条件就是Java的的持久化框架必须足够先进,持久化逻辑的引入不会干扰业务逻辑,我认为这在很长一段时间内将无法做到。在rails中能够将DAO去掉的原因就是rail中实现持久化逻辑的代码很简洁直观,这也与ruby的表达能力强有关系。DAO的另外一个好处隔离数据库,这可以支持多个数据库,甚至可以支持文件存储。基于DAO的这些优点,我认为,即使将来Java的持久化框架做得足够优秀,使用DAO将持久化逻辑从业务逻辑中分离开来还是十分必要的,况且它们本身就应该分离。

        争论的焦点到了DAO上,确实,实践中很多项目最终实施DDD的结果就是把所有的DAO重命名为Repository。但是我认为DAO和Repository很像,但是不是一个东西,因为它们出发点不同。

为什么要有DAO?
        因为之前,很早之前,我们对于框架中立性还很受用。DAO给了我们可以随时把Hibernate换成ibatis的幻觉,所以我们要有一个地方隔离了框架。
        而且DAO集中了所有的查询,方便了性能调优人员。同时也鼓励了查询的重用,同样方便了调优。

为什么要有Repository?
        在我看来,与其说Publication Repository,不如说Publications。Repository是一个集合对象,它封装了集合的逻辑。因为它具有封装性,所以它应该负责保持这个集合的状态,比如拒绝一些非法的的修改。Repository的入口是聚合根。

Java代码



class PublicationRepository {  
  public void save(Publication pub) {  
   if (hasSameName(pub)) {  
     throw new InvalidPublicationException();  
   }  
   dao.save(pub);  
  }  
}  

 


        另外,Repository只应该负责Aggregate Root。对于被Aggregate的对象,应该用Navigation,也就是在关系之间游走来获取。所以不是所有的查询都必须由Repository来完成,比如说:

Java代码



class Contact {  
  private List<ContactNote> contactNotes = new ArrayList<ContactNote>();  
  public void contactedBy(User accountManager, DateTime time){  
    ContactNote contactNote = new ContactNote(this, accountManager, time);  
    if (isDuplicated(contactNote)) {  
      throw new InvalidContactNote();  
    }  
    contactNotes.add(contactNote);  
  }  
  private boolean isDuplicated(ContactNote contactNote) {  
    // 查询contactNotes  
    return xxx;  
  }  
}  

 


        现状是,对象之间的关联不可查询导致了,很多这样的查询必须通过xxxDao,xxxRepository来完成。其实它们都不应该插手。

        理想情况下,只有业务开始的时候用repository加载对象,在结束的时候用repository把对象存储回去,中间都是领域对象在互相作用。而DAO,可以以Generic Query Builder的形式存在,不过和它之前被发明出来的意图已经不是一个东西了。

        DAO原本的作用就是隔离数据库的影响,没有业务逻辑。而Repository更抽象,从概念上来说是一个可以全局访问的集合,从这个意义上来讲对你所举Publication Repository,使用add(Publication pub)作为方法签名要更好一些。Repository也负责保持完整对象的完整性,PublicationRepository的例子也说明了这一点,另外一个例子,但从数据库重建一个对象时,由于外部原因,对象已经变得不完整,将它恢复为一个完整的对象或者直接抛异常也是Repostory的责任,它可以将这种保证对象完整性的责任委托给别的对象(如Factory)。
————————————————
http://www.shanhubei.com/archives/2791.html