DAO 模式和模型对象

2022-09-02 13:37:15

我已经查找了很多关于DAO模式的信息,我明白了它的重点。但我觉得大多数解释并没有说明整个故事,我的意思是你实际上会在哪里使用你的DAO。例如,如果我有一个User类和一个相应的UserDAO,它能够为我保存和恢复用户,这是正确的方法:

  • 控制器创建 User 对象并将其传递给 UserDAO 以将其保存到数据库

  • 控制器创建 User 对象,并在其构造函数中,用户对象调用 userDAO,以便将自身保存到数据库中

  • 这是一个代码异味,你缺少一个额外的类“UserManager”,控制器将要求它创建用户。用户管理器负责创建用户并要求用户DAO保存它

我真的觉得第三个选项是最好的,因为控制器负责的只是将请求委托给正确的模型对象。你最喜欢的方式是什么?我在这里错过了什么吗?


答案 1

根据我对DAO的经验,第一种方法是唯一正确的方法。原因是它具有最明确的职责,并且产生的混乱最少(好吧,一些非常受人尊敬的程序员认为DAO本身是混乱的。Adam Bien认为,已经在和进一步的DAO中实现的原始DAO模式大多是不必要的“管道”)EntityManager

方法 2 将模型绑定到 DAO,从而创建“上游依赖关系”。我的意思是,通常模型是作为单独的包分发的,并且(并且应该)不知道它们持久性的细节。与您所描述的模式类似的模式是活动记录模式。它在Ruby on Rails中被广泛使用,但在Java中还没有以同样优雅和简单的方式实现。

方法3 - 应该是什么?在您的示例中,Manager 执行 2 个任务 - 它具有用户工厂的职责,并且是持久性请求的代理。如果它是一个工厂,你需要一个,你应该命名它,而不是强加额外的任务。至于代理 - 为什么你需要它?UserManagerUserFactory

恕我直言,大多数命名的课程都有气味。名称本身表明该类没有明确的目的。每当我有命名一个类的冲动时,这都是一个信号,让我找到一个更合适的名字或认真思考我的架构。...Manager...Manager


答案 2

对于第一种方法;恕我直言,控制器在DAO对象上调用方法不是一个好的设计。控制器必须询问有关业务的“服务”级别对象。这些“服务”如何持久保存数据不是控制器关心的问题。

对于第二种方法;有时您可能只想创建对象,因此构造函数职责和持久职责不能像这样紧密耦合。

最后,管理器或服务对象是分层体系结构的良好抽象。这样,您就可以将业务流程分组到适当的类和方法中。

但对于 Play,case 类的伴随对象也是用作 DAO 的良好候选对象。这些对象的单例性质使其成为一个很好的候选对象。

case class TicketResponse(appId: String, ticket: String, ts: String)

object TicketResponse{
  implicit val ticketWrites = Json.writes[TicketResponse]

  def save(response: TicketResponse) = {

    val result = DB.withConnection {
      implicit connection =>

        SQL("insert into tickets(ticket, appid, ts)"
          +   " values ({ticket},{appid},{ts})")
          .on('ticket -> response.ticket, 'appid -> response.appId, 'ts -> response.ts).executeInsert()
    }

  }

}