18

这个问题很好地消除了我对此事的困惑,但我很难找到关于服务层的确切限制应该是什么的可靠来源。

对于此示例,假设我们正在处理书籍,并且我们希望按作者获取书籍。BookDataMapper可以有一个接受条件的通用方法get(),例如书籍的唯一标识符、作者姓名等。这个实现是相当简单的(逻辑上),但是如果我们想要有多个条件需要更复杂的查询呢?

假设我们想要获取某个作者在特定出版商下撰写的所有书籍。我们可以扩展该BookDataMapper->get()方法以解析出多个条件,或者我们可以编写一个新方法,例如BookDataMapper->getByAuthorAndPublisher().

是让服务层直接调用这些[更具体的]方法,还是在调用BookDataMapper->get()具有多个条件的更通用的方法之前解析条件?在后一种情况下,服务层将完成更多的逻辑“繁重工作”,从而使数据映射器相当简单。前一个选项会将服务层几乎完全减少为一个中间人,将条件逻辑留给数据映射器,如BookDataMapper->getByAuthorAndPublisher().

让服务层解析条件的明显问题是某些域逻辑会从数据映射器中泄漏出来。(这在此处的链接问题中进行了解释。但是,如果服务层要处理这些条件,则逻辑不会使其脱离模型层;$book_service->getByAuthorAndPublisher()无论如何,控制器都会调用。

4

2 回答 2

24

数据映射器模式只告诉你它应该做什么,而不是它应该如何实现。
因此,本主题中的所有答案都应被视为主观的,因为它们反映了每个作者的个人偏好。

通常尽量保持映射器的界面尽可能简单:

  • fetch(),检索域对象或集合中的数据,
  • save(), 保存(更新现有的或插入新的)域对象或集合
  • remove(),从存储介质中删除域对象或集合

我将条件保留在域对象本身中:

$user = new User;
$user->setName( 'Jedediah' );

$mapper = new UserMapper;
$mapper->fetch( $user );

if ( $user->getFlags() > 5  )
{
    $user->setStatus( User::STATUS_LOCKED );
}

$mapper->save( $user );

这样,您可以有多个检索条件,同时保持界面清洁。

这样做的缺点是您需要一个从域对象中检索信息的公共方法才能拥有这样的fetch()方法,但无论如何您都需要它来执行save().

没有真正的方法来实现映射器和域对象交互的“告诉不要问”经验法则。

至于“如何确保您确实需要保存域对象?” ,您可能会想到,这里已经介绍了它,并在注释中提供了大量的代码示例和一些有用的部分。

更新

如果您希望处理对象组,则应该处理不同的结构,而不是简单的Domain Objects

$category = new Category;
$category->setTitle( 'privacy' );

$list = new ArticleCollection;

$list->setCondition( $category );
$list->setDateRange( mktime( 0, 0, 0, 12, 9, 2001) );
// it would make sense, if unset second value for range of dates 
// would default to NOW() in mapper

$mapper = new ArticleCollectionMapper;
$mapper->fetch( $list );

foreach ( $list as $article )
{
    $article->setFlag( Article::STATUS_REMOVED );
}

$mapper->store( $list );

在这种情况下,集合是美化数组,能够接受不同的参数,然后将其用作映射器的条件。当映射器试图存储集合时,它还应该让映射器从这个集合中获取列表更改的域对象。

在这种情况下,映射器应该能够在所有可能的条件下构建(或使用预设的)查询(作为开发人员,您将了解所有这些条件,因此您不需要使其在无限的条件下工作)和为该集合包含的所有未保存的域对象更新或创建新条目。

注意:在某些方面,您可以说映射器与构建器/工厂模式有关。目标不同,但解决问题的方法非常相似。

于 2012-08-13T22:15:31.050 回答
5

我通常更喜欢这个更具体,比如:

BookDataMapper->getByAuthorAndPublisher($author, $publisher)

那是因为我不需要重新发明 SQL。数据库对此更好,并且数据映射器在这里负责应用程序的其余部分也不需要知道任何关于事物如何存储或查询的具体内容。

如果你让它更有活力,你很容易倾向于通过界面提供太多的功能。不好。

并查看您的应用程序。您会看到,不会有太多不同的查询。对于数据的主要部分,如果有的话,通常是大约 5-10 个例程。它的编写速度甚至比考虑一些实际上属于它自己层的动态系统要快得多。

于 2012-08-13T21:58:12.020 回答