4

What is the right concept of calling methods of parts in composition?

I have a class

class Body{
   Arm arm;
}

class Arm{
   public void waveArm(){}
   Finger finger
}

class Finger{
   public void moveFinger(){}
}

And I want to invoke moveFinger(). What is the correct way to do so? Is it

Body b;

b.arm.finger.moveFinger()

Or I should create wrappers, e.g.

Body::moveFinger(){ arm.moveFinger();}
Arm::moveFinger(){ finger.moveFinger();}
b.moveFinger()

Using the first way, we can get really long chaining.

However using second method, for every new method I would have to create a lot of wrappers (up to n where n is the depth of the parts tree - or how to call it).

What is the correct way or how to chose between those two?

2

You don't talk to a person's arm and tell it to move a finger. The arm belongs to a person so you talk to the person. But you wouldn't ask a person to hand you the arm so you can move one finger on it. Neither would you tell a person directly how to move individual fingers - that would be a highly inefficient way to do anything useful. What you do is talk to the person on the appropriate abstraction level and say something like "make me a sandwich". The person will then figure out how to move arms and legs and fingers to solve that task.

The point is you shouldn't need to talk to individual components in a composition from the outside. You talk to the unit as a whole, and how it is internally composed is an implementation detail. If you need to talk directly to an internal component then something is wrong in the design.

Now if you go inside the body of the person and see how the brain communicates with the fingers, you will notice that the brain can send direct signals to each individual muscle. From the perspective of the brain, arms and fingers are on the same abstraction level, so is not really an appropriate model to say the fingers are sub-components of the arm.

To translate this back into design principles: If you have a composition, you should not talk directly to individual parts from the outside. The methods exposed should be operations on the whole. If you genuinely need to talk to specific parts, then composition should probably not have been used in the first place, since you can't really encapsulate the parts.

Creating wrappers which forwards a message from the whole to a specific part is just cheating - you still have a bad design, even if you reduce the amount of dots.

  • Could you provide a concrete example with the finger/arm example? – Adam B Nov 5 '18 at 3:46
1

b.arm.finger.moveFinger() violates the Law of Demeter, since apparently you're exposing body's internal structure.

But the first question you should ask yourself is do you really treat body as a data bag, a structurer? Probably it has some behavior involved when getting an arm? Could any decoration or state be involved? Say, you could have default arm, strong arm, injured arm, etc? Behavior is rich, composable and modifiable. Structure is static. So if you decide to treat your body as an object responsible for providing an arm somehow, than it's not a structure revelation, it's behavior. In this case b.arm().finger().moveFinger() would be just fine and would not be a violation of the aforementioned law.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.