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.