我怎样才能掌握纯OOD的概念?

发布于 2024-11-03 07:18:16 字数 1565 浏览 0 评论 0原文

我在理解纯 OOD 的概念上仍然存在一些问题。

假设我们有一个人类类,我们生活在一个有时人类行走(大脑命令腿)、有时树木消失(人类注意到这一点)、有时人类随机互相撞击的世界。

前两种情况确实很简单:

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 中呢?如果安娜击中了鲍勃并且鲍勃摔倒了,那么摔倒既不是安娜也不是鲍勃直接造成的。这是由撞击、失去平衡和物理原因引起的。

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

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 的状态时,你们如何处理这种情况。

I still have a little problem grasping the concept of pure OOD.

Let's say we have a class Human and we live in a world where sometimes the human walks (the brain commands the legs), where sometimes trees disappear (the human notices that) and sometimes humans randomly hit each other.

The first two cases are really a no-brainer:

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);
};

Now I've got a really bad problem with the hit method. Of course it's nice that you can say

anna.hit(bob);

Up until here I think it's nice (please complain if something's bad) and reads like prose (which good OOP code should). But how do you transfer the hitting into OOP? If Anna hits Bob and Bob falls down then the falling down is neither directly caused by Anna nor Bob. It's caused by the hit, a loss of balance and by physics.

I know only 2 options for this case, but somehow I think both suck:

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(); }
}

In this case Anna "falls down" Bob. But this totally doesn't make any sense. It's not like Anna grabs Bob's body and moves it towards the ground. But there's another option:

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(); }
}

In this case Bob's body "notices" that the hit is causing him to fall to the ground, he'll then "move himself" to the ground. I think this is better than the first option but this still somehow doesn't feel right.

So please, smart OOP folks, explain to me, how do you handle cases when in the real world A modifies the state of B but in the OOP world only B should modify the state of B.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

饮惑 2024-11-10 07:18:16

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

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

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

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

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

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

I think that you are falling into the trap of trying to model the "real" world in classes without having a purpose to your design.

What is your program supposed to do? Once you've worked that out, then you can start to design which aspects of the real world you want to model and which parts of the real world don't matter and don't need to be modelled. Making a class map onto a concrete real world object type just because it is easy to visualise is often a mistake. You only have to model concepts that matter to your program.

OOD is about using techniques such as abstraction and polymorphism to allow objects to interact with each other without having to know about each other's implementation.

In your implementation you need to decide what behaviours you want to model and what knowledge each object wants. For example, you might want a human to work out whether he wants to fall down based on how hard he is hit.

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

Note that the thing that hits me doesn't need to know or care what effect it will have on me. That's my reaction to the hit. I've also modelled a "hit" object because it makes sense to my program. Anything can hit me by creating a Hit object and making me receive it. In the future I can be hit by a bus or a train without any changes to my class.

恍梦境° 2024-11-10 07:18:16

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

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

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

  2. 在接下来的几个周期中,鲍勃在他的下落状态中保持直线下降。

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

  4. 然后,bob 的状态更改为 cries_for_mommy

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

I think your dilemma arises because you are not modelling the passage of time. Everything happens at once when you do anna.hit(bob).

If you modelled your entities as running their own state machines, then things will start looking more like reality:

  1. anna.hit(bob) causes bob's state to change to falling.

  2. For the next few cycles, bob keeps plummeting in his falling state.

  3. Eventually bob's state changes to on_ground.

  4. Then bob's state changes to cries_for_mommy.

Check out the State design pattern for ideas on how to implement start charts in an OO language. The "Gang of Four's" Design Patterns book covers this topic.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文