MVC与DAO/VO-控制器应该与哪个DAO对话


MVC with DAO/VO - Which DAO should the Controller talk to?

背景:

我有一个设计模式的问题,我希望有人能解决。我用PHP编程,但我相信DAO/VO在Java中很流行。

我已经使用MVC很多年了。我设计了一个购物模式,它是MVC,但使用了过程编程。因此,最近我决定再次使用OO开发cart。

问题:

我面临的问题是,我的Product类没有RetrieveAll()方法。例如,如果我列出了10个产品,我会从哪个实例调用RetrieveAll()方法?我有10个选择。

解决方案:

因此,我找到了DAO/VO模式。除非我对这个模式研究得不够——我相信每个DB表都必须有一个Model+DAO。任何模型或DAO都不应该知道另一组模型或DAO。因此被封装。该模式非常合理,将数据库层从模型中拉开。

然而。在购物车中,我的产品被分配了类别。一个类别可以是电子产品、服装等。

共有3张表:-类别(pid,名称)-类别项目(iid,名称)-类别链接(pid,iid)

从MVC方法来看,控制器应该与哪个DAO对话是没有意义的?

应该是:

  • 控制器与所有3个DAO进行对话,然后将适当的数据结构返回给View
  • 或者DAO应该(以某种方式)相互对话,并将单个结构返回给Controller

请看这里的例子(图片)

我不知道你说的VO是什么意思。它是价值对象吗?

我是DDD(领域驱动设计)方法的超级粉丝(尽管我不认为自己是这方面的大师)。在DDD中,您有所谓的服务服务是在您的域上操作并返回数据的操作。服务将操作封装在您的域数据中。

与其让控制器执行所有的域逻辑,比如检索什么项目、使用什么DAO等等(为什么控制器无论如何都应该关心域?),它应该封装在自己的域中,在DDD的情况下,封装在服务中。

例如,您想要检索"电子产品"类别的所有类别项目。你可以写一个看起来像这样的控制器(如果代码有无效语法,请原谅我,这是为了举例):

public function showItemsByCategoryAction($categoryName) {
  $categoryId = $categoryDAO->findByName($categoryName);
  if(is_null($categoryId)) {
    //@TODO error
  }
  $itemIds = $categoryLinkDAO->getItemsByCategoryId($categoryId);
  if(empty($itemIds)) {
    //@TODO show error to the user
  }
  $items = $categoryItemDAO->findManyItems($itemIds);
  //@TODO parse, assign to view etc
}

这至少引入了两个问题:

  1. 控制器是FSUC(胖笨丑控制器)
  2. 该代码不可重复使用。如果你想添加另一个表示层(比如开发人员的API、网站的移动版等),你必须复制并存储相同的代码(除了视图呈现的部分),最终你会得到封装这些代码的东西,这就是服务的目的

有了服务层,同一个控制器可能看起来像

public function showItemsByCategoryAction($categoryName) {
  $service = new Item_CategoryName_Finder_Service();
  $items = $service->find($categoryName);
  if(empty($items)){
    //@TODO show empty page result, redirect or whatever
  }
  $this->getView()->bind('items', $items);
}

控制器现在是干净的、小的,并且所有的域逻辑都封装在一个服务中,该服务可以在代码中的任何地方重用。

现在有些人认为控制器应该对DAO一无所知,只通过使用服务与域通信,另一些人则认为可以从控制器调用DAO,没有严格的规则,决定什么更适合你。

我希望这对你有帮助!祝你好运:)

我也不是DDD专家,但这是我的看法。这就是应用存储库模式的情况。基本上,域不知道也不关心DAO或任何其他与系统相关的东西。最多了解存储库接口(应该在基础设施级别实现)。

控制器知道域和存储库。存储库封装了所有与数据库相关的内容,应用程序只知道存储库本身(实际上应该注入作为实际实现的接口)。然后,在存储库中,您可以使用您认为合适的DAO。存储库只接收和发回应用程序/域对象,与数据库访问实现无关。

简而言之,任何与数据库相关的东西都是一部分,它是存储库的实现细节。

在决定哪个dao方法应该转到哪个dao类时,可以考虑返回类型,因此控制器应该与哪个dao对话:

每个数据实体实现一个DAO类更干净,

CRUD操作应该进入Dao类,C创建、R读取、U更新、D删除

读取操作与创建、更新、删除不同,大多数情况下,读取操作在考虑返回内容时都有不同的风格。

对于Read操作,在决定哪种dao方法应该转到哪种dao类时,可以考虑返回类型

以下是一些商业实体和Dao

Exchange -> ExchangeDao
Company -> CompanyDao
Stock -> StockDao