【问题标题】:How can I grasp the concept of pure OOD?我如何才能掌握纯OOD的概念?
【发布时间】:2011-08-11 12:11:44
【问题描述】:

我对纯 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 的状态时,你如何处理情况。

【问题讨论】:

  • 如果树木消失了,周围没有人,它们会发出声音吗?
  • @Emile:真正的问题是:树木是如何消失的?
  • @darioo:如果不是人类,它们最初是如何出现的?

标签: c++ oop ooad


【解决方案1】:

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

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

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

  2. 在接下来的几个周期中,bob 的falling 状态不断下降。

  3. 最终 bob 的状态更改为 on_ground

  4. 然后鲍勃的状态变为cries_for_mommy

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

【讨论】:

    【解决方案2】:

    我认为你陷入了试图在类中对“真实”世界建模而没有设计目的的陷阱。

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

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

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

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

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

    【讨论】:

    • +1 用于创建 Hit 对象。对象不必引用物理对象。任何可能变成名词的东西都可以是对象,无论是物理的还是概念的。
    • +1 表示关注“告诉不要问”。 @Kiralein:阅读 pragprog.com/articles/tell-dont-ask 以获得此类问题的一般答案。
    • @Daniel T.:感谢您提供的额外信息,我会标明 - erm - 阅读:3
    猜你喜欢
    • 1970-01-01
    • 2013-09-02
    • 1970-01-01
    • 2018-01-14
    • 2018-12-27
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    相关资源
    最近更新 更多