【问题标题】:question of design / structure of application and separation of concerns应用程序的设计/结构问题和关注点分离
【发布时间】:2009-12-17 17:01:07
【问题描述】:

所以这个问题是从这里 (how to deal with multiple event args) 开始的。这个问题让我开始思考这个问题,但它的不同之处足以保证它自己的线程。

我正在创建一个游戏(出于娱乐和学习目的),并且想知道我是否使用了良好的设计标准。我想我可能在关注点分离上使用了 OTT,或者只是把整个事情弄错了,但我希望不是这样。重写它没有问题,因为我想学习“最佳实践”及其实际应用。

编辑

让我稍微解释一下这款游戏,它基于 Jawbreaker,这是一款在许多手机上都能找到的游戏 (quick demo found here)。目标是选择成组的球,将它们从比赛中移除并获得尽可能多的分数。

我正在尝试将其扩展一点,并设置不同类型的板,球以不同的方式移动,不同的球类型,球可能只是去他们被告知的地方,或者他们可能会沿途做一些事情。

下面是我创建的对象的结构,第一行显示 DLL 及其对象,第二行显示这些对象引用的内容:


(来源:ggpht.com

这是我做 UML 的尝试:

alt text http://yuml.me/3279d2ac

Click here to link to full page for UML, makes it a little larger and hopefully easier to read

Objects DLL 包含游戏中使用的基本对象、球和棋盘。它们不包含任何关于它们如何对情况采取行动/反应的逻辑(球确实实现了 CompareTo 和 Equals 方法)。 IBall 的实现可能有 X 个(对于 IBoard 也是如此,尽管我想象的不会那么多)。

InstanceManager DLL 被用作创建对象的一种方式,不确定这是 100% 需要的,它本可以在对象 DLL 中使用。工厂是具有各种重载方法来创建 IBall 对象的静态类。 BallFactory 可以采用 BallType Enum、A Drawing.Color 对象等。 BoardFactory 非常相似。 Jawbreaker 是一个单例对象,它处理诸如保存一个非常经常使用的随机对象和一些 GameConfiguration 数据之类的事情(与本主题不太相关)。

引擎 DLL 是大部分工作发生的地方。 LogicFactories 使用 BallType 和 BoardType 对象来创建相关的逻辑对象。逻辑对象用于控制 IBall 和 IBoard 对象的工作方式。 BallLogic 告诉球在其事件触发时它可以做什么。例如,当一个球被选中时,会在 Ball Logic 上调用一个方法,说明板上 Y 上的 Ball X 已被选中。然后,球可以做任何它的类型的球应该/可以做的事情。 BoardLogic 非常相似,它处理董事会的行为方式。

引擎对象是另一个单例,它是 GUI 与整个游戏交互的方式。 GUI 不会直接实例化任何其他对象。

总而言之,IBall 和 IBoard 类只保存有关它们的数据,Logic 类处理所有功能。

我想知道的是:

1) 这是一种明智的做法吗?

2) (通常)逻辑是否应该与对象/数据分开?

3) 我在关注点分离方面做得太过分了吗?

4) 关于设计/结构的任何其他 cmets

编辑

我使用几个单例的部分原因是为了方便在一个地方访问数据而无需一直保持对象,也只是因为它是一个单一的游戏,不会扩展到高端或跨多台机器。我确实知道它们不是很好,也不是我经常使用的东西,但感谢 cmets。

感谢您的想法和反馈。

【问题讨论】:

  • 虽然你对你的设计的解释很清楚,但我认为如果你把你的设计作为一个 UML 类图(比如说)你可以更清楚地理解你的信息。在阅读文本时,我必须在脑海中不断绘制箭头以了解所有这些类如何交互。
  • 非常好,今晚会这样做并尽快把它放上去。谢谢萨提什
  • 看看 Visual UML 或 Netbeans UML,它将帮助您将类设计为 uml。
  • 您的课程似乎没有那么复杂,所以我会使用yuml.me 来创建图表。
  • 真的很喜欢yuml.me,很酷。谢谢

标签: design-patterns separation-of-concerns


【解决方案1】:

您的故障看起来正朝着正确的方向发展。但是,我不确定您是否尝试将演示文稿中的数据与逻辑分开。看看 MVC、观察者和策略模式。

记住这一点:当您将应用程序设计为松散耦合时,需要权衡取舍。您可以轻松地扩展应用程序,但会降低性能和内存使用量。另外,我讨厌这样说,但不要创建不必要的接口。如果您知道您现在或稍后将在创建接口时扩展对象的功能,如果在实现它之前不考虑它。

【讨论】:

  • 将看看 MVC 观察者和策略模式,我明白你对接口的看法,在这种情况下,几乎所有接口都立即被许多类使用。谢谢
  • 看起来我在不知不觉中走了一半的战略道路。我要重构一些东西,所以我做得正确。完全有道理,那么我只需要一个具有不同策略的 Ball 对象
【解决方案2】:

如果不更好地了解您想要做什么,就很难批评您的设计。我知道它涉及球和板,但除此之外,我不知道。

尽量避免单例。是的,我知道 GoF 书中列出了它,并且我知道这是一种常见的模式,但根据我的经验,它最终变成了一种反模式。

您提到 IBall 和 IBoard 没有任何关于它们如何交互的逻辑。这是否意味着他们没有任何方法?他们的方法只是他们私有数据的 getter 和 setter 吗?如果 IBall 和 IBoard 只是结构(或它们的等价物),那么它们不需要是接口。您能否详细说明您可以向 IBall 和 IBoard 发送哪些消息?

2) (通常)逻辑是否应该与对象/数据分开?

有时。如果您有普通的旧数据,那么将逻辑与普通数据分开就可以了。当然,那么您就不再做 OOP 了——您正在编写过程代码。我认为您正在努力避免将任何行为硬编码到 Ball 中。也许其他实体应该负责决定球的交互方式,但您仍然有空间让 Ball 参与决策。这就是策略模式(以及其他模式)发挥作用的地方。想想现实世界中的事情是如何运作的——一个物理球和一个物理板如何协调它们的交互?如果他们互相交谈,他们会说什么?看看你是否可以在你的代码中实现它。

最后,谈谈设计。我认为想要“正确设计”是件好事。另一方面,这是成为architecture astronaut 的途径。考虑一下您的代码库目前存在哪些问题。

  • 重构难吗?
  • 添加新类型的东西很难吗?
  • “硬连线”太多了吗?

设计不存在于真空中 - 它受世界当前状态的影响。只要看看人们想出的一些疯狂的手机概念艺术,你就会看到糟糕设计的好例子。手机受到当前技术的限制,无视现实世界限制的设计无非是梦想。在软件中也是如此。注意代码告诉你它需要什么,你会做得很好。

您编写(并完成)的软件越多,您将拥有越多的经验,并且您的审美意识就会越好。不要让“做错”的恐惧阻止你完成你的软件。坚持下去,让它发挥作用,然后看看你从这个过程中学到了什么。

【讨论】:

  • 感谢您的好评。我将在问题中添加一些额外内容以扩展它。
  • 我认为我采取的方法不是最好的主意。我明白我为什么要这样做,并认为如果我只是退后一步,策略模式将是一种更好的方法。将它放入 Ball and Board 意味着我删除了那里的继承,并摆脱了整个 DLL 的点点滴滴。谢谢
  • 我想我明白你的意思了。从您的 UML 看来,您的板子有一个 BoardType 字段,而您的球有一个 BallType 字段。我的猜测是这些是枚举,并且您在代码中的某处使用 if 或 switch 语句来根据 BoardType 字段执行不同的操作。这通常是策略模式的完美案例。该策略是一个接口,每个枚举值都有一个实现。枚举消失。这将决策从显式的“if”测试推向了多态性领域。
  • 你好 Daniel,你说得对,它们是 Enum,在 Factories 中用于决定创建哪种类型的对象(switch 语句)。不过,我看不到您完全摆脱 Enum。如果我只有一个具有不同 IBallStrategy 的 Ball 对象,BallFactory 是否还需要枚举(或其他东西)来决定在创建球时使用什么策略?
  • 圣诞节在城里购物并意识到我哪里出错了......我仍然需要一个 IBall 和各种实现,每个类都明确说明它的策略是什么。我唯一的问题是如何创建一个随机球,我想我需要使用反射来获取所有球类型并随机选择一个。
猜你喜欢
  • 1970-01-01
  • 2015-11-10
  • 2015-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多