5

我在理解纯 OOD 的概念方面仍有一点问题。

假设我们有一个 Human 类,我们生活在一个世界中,有时人类会走路(大脑控制腿),有时树木会消失(人类会注意到),有时人类会随机互相撞击。

前两种情况真的很简单:

class Tree {
  private:
    void disappear()
    {
       // call onTreeDisappeared() for all human observers
    }
};

class Human {
  public:
    // The human notices that a tree disappeared
    void onTreeDisappeared();
  private:
    int x, y, z;
    // Human wants to walk forward
    void moveForward();
    // Hit another human, possibly causing him to fall down
    void hit(Human &target);
};

现在我的 hit 方法遇到了一个非常糟糕的问题。当然,你可以说很好

anna.hit(bob);

直到这里我认为它很好(如果有什么不好请抱怨)并且读起来像散文(好的 OOP 代码应该)。但是如何将命中转移到 OOP 中呢?如果 Anna 撞到 Bob 并且 Bob 摔倒了,那么摔倒既不是 Anna 也不是 Bob 直接造成的。它是由撞击、失去平衡和物理引起的。

对于这种情况,我只知道 2 个选项,但不知何故,我认为两者都很糟糕:

public: void fallDown()
{ z = 0; }

public: void hit(Human &target)
{
  bool targetFallsDown = true; // could be random or any algorithm you like
  if(targetFallsDown)
  { target.fallDown(); }
}

在这种情况下,安娜“摔倒”鲍勃。但这完全没有任何意义。这不像安娜抓住鲍勃的身体并将其移向地面。但还有另一种选择:

private: void fallDown()
{ z = 0; }

public: void onHitCausesMeToFallDown()
{ fallDown(); }

public: void hit(Human &target)
{
  bool targetFallsDown = true; // could be random or any algorithm you like
  if(targetFallsDown)
  { target.onHitCausesMeToFallDown(); }
}

在这种情况下,鲍勃的身体“注意到”撞击导致他倒在地上,然后他会“自己”倒在地上。我认为这比第一种选择要好,但这仍然感觉不对。

所以,请聪明的 OOP 人向我解释一下,当在现实世界中 A 修改 B 的状态但在 OOP 世界中只有 B 应该修改 B 的状态时,你如何处理这种情况。

4

2 回答 2

10

我认为您陷入了试图在课堂上对“真实”世界建模而对您的设计没有目的的陷阱。

你的程序应该做什么?一旦你解决了这个问题,你就可以开始设计你想要建模的现实世界的哪些方面,以及现实世界的哪些部分无关紧要并且不需要建模。仅仅因为它易于可视化而将类映射到具体的现实世界对象类型通常是错误的。您只需对对您的程序很重要的概念进行建模。

OOD 是关于使用抽象和多态等技术来允许对象相互交互而不必了解彼此的实现。

在您的实现中,您需要确定要建模的行为以及每个对象想要的知识。例如,您可能希望一个人根据他受到的打击程度来确定他是否想摔倒。

void Human::receiveHit(Hit hit)
{
    if (hit.IsBigForThisWeight(this->weight))
        this->fallDown();
}

请注意,击中我的东西不需要知道或关心它会对我产生什么影响。这就是我对打击的反应。我还模拟了一个“命中”对象,因为它对我的程序有意义。任何事情都可以通过创建一个Hit对象并让我接收它来打击我。将来我可能会被公共汽车或火车撞到,而我的班级没有任何变化。

于 2011-04-23T14:46:42.370 回答
1

我认为你的困境出现是因为你没有模拟时间的流逝。当你这样做时,一切都会立即发生anna.hit(bob)

如果您将实体建模为运行自己的状态机,那么事情将开始看起来更像现实:

  1. anna.hit(bob) 导致 bob 的状态变为falling.

  2. 在接下来的几个周期中,鲍勃的状态一直在下降falling

  3. 最终 bob 的状态变为on_ground

  4. 然后 bob 的状态变为cries_for_mommy

查看State设计模式,了解如何在 OO 语言中实现开始图表。“四人帮”设计模式一书涵盖了这个主题。

于 2011-04-23T14:40:49.300 回答