Tight coupling between parent and children: always to be avoided?

Say we consider two inherently coupled elements, using a real-life like example:

  • Body
  • PhysicalIllness

Note: the following code is pseudo-Java for the sole purpose of syntax-coloring, pure syntax doesn’t really matter here.

Body is a class that holds several basic properties, such as stamina, focus, etc., plus an array of PhysicalIllness representing all the illnesses it has contracted.

class Body {    int focus    int stamina     PhysicalIllness[] physicalIllnesses } 

PhysicalIllness is an abstract class, extended by concrete illnesses. Everything they do/react to depend on their host body. They are born inside a body, they “live” within it and their existence doesn’t mean anything outside of a body.


In such a scenario, wouldn’t having a Body instance injected into PhysicalIllness‘s constructor, and stored as a (say, host_body) reference used throughout the life of the illness, be fine? The illness could then respond to life events (say sleeped, hour_elapsed) on its own and impact its host body accordingly:

abstract class PhysicalIllness {    Body hostBody     PhysicalIllness(Body hostBody) {      this.hostBody = hostBody    }     void onAcquired() {}    void onHourElapsed() {}    void onBodySleeped() {}    void onGone() {} }  
class Headache extends PhysicalIllness {   void onAcquired() {     this.hostBody.focus -= 10   }   void onHourElapsed() {     this.hostBody.focus += 2   }   // ... } 

Tight coupling actually seems natural to me here. However, it does produce a cyclic/circular dependency, as Body holds references to PhysicalIllness instances and PhysicalIllness also holds a reference to its “parent”, its host body.

Could you people point to any downside of designing things this way, in terms of code maintenance/unit-testing, flexibility, or anything else? I realize there are other answers about this, but since every scenario is different, I’m still unsure if they apply here as well.

Alternative (without circular dependency)

One alternative would obviously be to remove the coupling by having PhysicalIllness instances be notified of every event by the body (which would pass itself as argument in the process). This requires every method of PhysicalIllness to have a Body parameter:

abstract class Illness {    void onAcquired(Body hostBody) {}    void onHourElapsed(Body hostBody) {}    // ... }  
class Headache extends Illness {   void onAcquired(Body hostBody) {     hostBody.focus -= 10   }   void onHourElapsed(Body hostBody) {     hostBody.focus += 2   }   // ... } 
class Body {   // ...    void onHourElapsed() {     for (PhysicalIllness illness in this.physicalIllnesses) {       illness.onHourElapsed(this);     }   }    // ... } 

I feel like this is clunky and actually less logical, because it means a physical illness can exist outside of a body (you can construct one without a host body), and therefore all methods require the “obvious” host_body parameter.

If I had to summarize this post with one single question: should tight coupling and/or circular dependency between parent/children components be avoided in all situations?