【问题标题】:Pattern to build a large hierarchy of objects构建大型对象层次结构的模式
【发布时间】:2011-01-09 03:07:58
【问题描述】:

我有一个问题,涉及到一个比较大的对象层次结构如下:

  • 游戏有一个社区管理员
  • 社区经理有一个网络
  • 网络有很多玩家
  • 网络有很多朋友
  • 玩家有一个策略经理
  • 玩家有一个记忆
  • 玩家有一个社区
  • 社区有很多玩家
  • 战略经理有很多战略

如您所见,层次结构相对复杂,并且至少在一个地方是循环的(网络有许多代理,它们具有一个邻域,而邻域又具有一个网络)。目前我在GameFactory 类上使用静态构造方法来构造整个层次结构,但我很确定这是最不灵活的方法!

在构建复杂的对象层次结构方面,最好使用什么模式?我已经阅读了Factory MethodAbstract FactoryBuilder 模式,我认为其中一种工厂模式是合适的,但我真的不知道如何将它应用到如此复杂的层次结构中?

在我看来,系统的每个部分都需要许多工厂,但这会导致工厂类的集合反映模型类。


编辑:从目前给出的建议中的讨论中可以清楚地看出,我应该更多地解释为什么我需要工厂来构建我的对象层次结构,而不是允许构造函数自己构建它们的依赖关系。

这是因为我使用依赖注入来帮助测试驱动开发。我正在采用模拟方法进行测试,这需要能够注入代表对象依赖项的模拟,因此我必须避免在任何构造函数中使用new

从目前给出的建议看来,有很多可能的方法:

  • 在每个类中创建一个辅助构造函数,用于构建正在构造的对象所需的任何依赖项。这允许依赖注入和简单的对象层次结构构造。
  • 有一个工厂类(可以是单个工厂类,也可以是它们的层次结构,具体取决于所使用的工厂模式的类型)映射到每个域类以处理其构造。
  • 使用这些方法的组合,其中工厂类仅在构造过程中存在变化时创建(即在某些情况下需要构造不同的子类)

我倾向于走最后一条路线。在这种情况下采取的最佳方法的共识是什么?


编辑:我正在撤销当前的答案(Patrick Karcher 的答案),因为现在这个问题的重点已经澄清,所有建议都不是完整的答案。

【问题讨论】:

  • 为了清楚起见,最好提出一个新问题(参考这个问题)。

标签: design-patterns oop architecture


【解决方案1】:

了解为什么你需要一个工厂是很重要的。与许多“良好”实践一样,工厂可以产生某些优势,这些优势有时需要,并且只有通过正确使用才能获得。

factory 通常是对象模型中的另一个类。例如,您通常会得到一个 player,因为您有一个带有 players 集合的 neighborhood,并且您将遍历它,为玩家做事。或者您从 network 对象开始。或者(我猜)你已经有一个玩家,你得到了一个友谊,你又得到了玩家。所以 friendshipplayer 对象的工厂,而 playerfriendship 对象的工厂!

尽管有时您确实有理由使用 非域专用工厂对象。您可能有一个工厂类作为开始逻辑的对象的起点。当您的某些对象需要以许多棘手的方式实例化并且工厂是组织它们的好方法时,通常会使用它们。有时您的对象需要使用例如数据层、用户和上下文进行实例化,而工厂可以维护这些东西,制作您的对象,并使您不必在许多不同的构造函数中重复自己。有时,工厂可以自动生成各种工具所需的通用引用。

工厂有一个用途正在迅速普及,值得特别提及。这是使用工厂类向inject dependencies 添加一层误导,特别是对于单元测试

我的建议是,如果您没有明确的理由使用工厂对象,请不要担心。只需使用良好的构造函数构建您的对象。然后很自然地添加返回相关对象的属性;这些将是你的第一家工厂。这可能是一个很好的例子,说明你一开始不想担心设计模式;设计模式不会带来成功。你做。与各种工厂模式一样,模式可以提供帮助,但不能取代基本的面向对象思维。

对于为什么需要专用工厂对象,您是否有特定的原因?

【讨论】:

  • 我以前不认为它是相关的,但是,是的,我在整个模型层次结构中使用依赖注入,因为我试图在整个模型中使用行为驱动的开发方法。据我了解,注入模拟需要依赖注入。我想问题是是否有两个构造函数,一个用于依赖注入,另一个用于构建自己的依赖关系的对象,或者是否使用工厂来生成和提供依赖关系。前者是一种常见的方法吗?我更倾向于后者。
  • 你提到的每个选项都可以很好地使用。我更喜欢构造函数,而且如果可以的话,我更喜欢有一个构造函数(或者如果有多个构造函数,则依赖项以相同的方式注入。)我的大多数对象都是由“工厂”(通常是其他业务对象)制作的使用构造函数构造并返回这些对象,但构造函数使对象自包含。这具有帮助类成为真正的黑匣子的实质性优势。
  • 在我当前的项目中,我所有进行数据访问的类都是用数据对象构造的。该页面会自动为我创建它并将其放置在我的用户上下文对象中,这是我的大多数其他对象的起点。在整个页面中,我通常不会自己实际注入它,因为我有一大串创建其他对象的对象。注入在生产中有点好(它很好地汇集了连接),但在测试中它很棒。而且因为它在构造函数中,即使它通常是无论如何制造的,我也有完整的 unit-level 控制权。我喜欢它。
【解决方案2】:

如果没有任何变化,即。如果你的构建过程是固定的,我会推荐最简单的方法:让对象自己负责构建它们的依赖对象,并建立链接(可能是双向的)。

示例:对于具有子集合的父对象,父对象可以有一个 addChild 方法来确保双向关系的一致性:

  1. 获取孩子的前一个父母;如果不为 null,则从该旧父级中删除子级。
  2. 将子项中的父字段更改为新的父项
  3. 将子项添加到新父项的子项集合中。

如果有变化,比如在某些情况下应该使用的子类,那么您必须准确定义变化的内容。只有在您找到了您的确切需求之后,才会出现正确的模式。 :-)

最后一部分我们可以提供帮助,但您是唯一可以提供所需信息的人... ;-)

【讨论】:

  • 正如刚才对 Patrick 所说,我实际上需要依赖注入,这就是我采用工厂路线的原因。对不起,我应该在我最初的帖子中说清楚。除此之外,一些领域类别确实有所不同,特别是玩家。每个玩家都有一种选择游戏结果的方法,目前我有一个玩家类别的层次结构。这是否意味着我应该有一个工厂来处理生成玩家并让构造函数处理其他实体?我也不确定依赖注入在哪里适合......
  • @toby 好的。你认为你会用这个必要条件更新你的问题,为读者提供一些背景信息,并解释为什么选择一个解决方案吗?
【解决方案3】:

KLE 根据关系的静态程度以不同方式处理它是正确的。我要补充一点,工厂类通常会镜像对象模型。将它们视为知道如何连接模型的不同类的智能对象的简单方法。

【讨论】:

  • 这是一种常见的做法吗?每个域类都有一个工厂类层次结构似乎很臃肿?
  • 这很常见。另一种选择是让物体拥有更多的智能,然后导致不同类型的膨胀。最好的例子是期望一个 Circle 对象知道如何绘制自己。它很快导致类负责所有交互,如序列化或变形。这样的代码很快使课程的初始焦点相形见绌。最好将此类行为集中在单独的类中。最后,使用工厂等工具可以帮助您保持代码所需的耦合和内聚水平。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多