应该何时将对象作为另一个对象的成员包含在内,何时应该将其作为独立对象?

时间:2011-03-17 05:27:50

标签: oop model-view-controller class-design composite

一个示例问题:

在Stack Overflow上,问题页面显示了许多不同的答案。在显示这些答案时,该站点还提供有关答案作者的信息。这意味着虽然给定用户的徽章数量与答案本身无关,但仍需要检索该数据才能显示该页面。

从我所看到的,有三种不同的方法可以在模型中提取这些视图数据:

  1. Post对象可以包含完整的User对象作为成员。然后,视图将按如下方式访问用户:$post->user->getReputation()。这看起来更干净,因为Controller可以只是请求帖子并完成它,但效率低,因为Post可能总是需要一个成熟的用户。我认为如果User对象相对较轻,它可能会很好。那么问题是您需要将用户检索代码复制为Post检索查询的一部分。

  2. Post对象只能保存用户的ID。当Post或Posts返回到Controller时,Controller可以从返回的集合中提取唯一的用户ID,并将它们传递给用户工厂。然后,返回的User对象将作为单独的集合与原始Posts一起传递给View。然后,该视图可以使用$users[$post->getUserId()]->getReputation()之类的内容获取用户信息。

  3. 混合方法:在Post对象中包含User对象,但具有唯一的id提取和用户检索作为Post检索方法的一部分。即Post::getPosts()将获取所有相关帖子并将其转换为具有空用户成员的对象,然后它将提取所有用户ID并将其传递给User::getUsers(),然后在返回之前将用户分配到相关帖子一组帖子给来电者。

  4. 我想我得到的是,我怎么知道对象何时需要从根本上包含另一个对象?是不洁净/代码气味,而不是单独返回这样的相关对象,没有任何对象知道另一个已被检索。我倾向于单独的检索概念 - 它似乎是最有效的 - 但它确实感觉它们太相关而无法理解。

3 个答案:

答案 0 :(得分:1)

还有一个介于1和2之间的解决方案。您可以为用户类设置延迟加载代理。使用此解决方案,您可以充分利用这两个世界,因为代理可以与真实的东西互换,因此根据情况您可以拥有对象本身或代理。

编辑: 我将尝试用一个例子来解释这个。

假设您有一个不需要用户信息的视图,那么您可以指示/配置您的工厂以便为仅包含ID的用户使用惰性代理(see wikipedia)。因此无需访问用户。

在另一个视图中,您偶尔需要访问用户信息,但仅针对某些帖子,此处再次指示/配置工厂以包含用户的惰性代理。 但是当您确实需要访问用户信息时,您可以访问代理对象,然后加载实际的用户对象并将消息重定向到它。

在另一个视图中,您需要发布信息和用户信息,因此在此指示您的工厂使用实际的用户对象。

答案 1 :(得分:0)

在我看来,这是依赖注入的另一种情况。一个足够普遍的想法,可以帮助你。

DEPENDENCY INJECTION WIKI

还要阅读有关控制反转的内容。

答案 2 :(得分:0)

为什么不在模型中添加可选成员来了解信息?您可以在不需要时忽略,并在需要时使用。