Question

  1. We know that composition is a synonym of loose coupling.

  2. From here I read coupling becomes stronger between the classes A and B when:

    A has an attribute that refers to (is of type) B.

  3. To implement a composition between 2 classes, we declare an attribute of one of them of a type of the other one as explained here.

But considering that (3) and the quoted phrase in (2) above are the same, isn't there a huge contradiction between (1) and (2) ?

Please clarify me if I am missing something

Was it helpful?

Solution

You are making some confusions in your 3 points:

  1. Composition alone is not a guarantee of lose coupling. Composition creates a dependency to an interface, so de facto some coupling. But the more generic the interface, the loser the coupling.

  2. Your quote is only one of several criteria. It applies if A and B are classes. However if B is an interface, the following quote of the same wikipedia article would apply (first sentence after the bullet):

    Low coupling refers to a relationship in which one module interacts with another module through a simple and stable interface and does not need to be concerned with the other module's internal implementation

  3. The UML composition expresses something different: it means a part/whole relationship with an exclusive ownership, independently of how this relationship is implemented (yes in practice, it's often via a reference but it has not to be so). In particular UML assumes that the death of the owning object would imply the death of the owned elements. So you are comparing an implementation concept (in 1 and 2 there is a reference, but no assumption about ownership) with a more abstract (although sometimes overlapping) design semantics.

So to keep it simple, and as a rule of thumb (and not as laws graved in the marble), for lose coupling:

  • prefer composition over inheritance, because inheritance is always a strong coupling (any change in the parent class might require a change in all the child classes) and furthermore, it's defined at compile time.
  • use interface segregation for the type you refer to, in order not to have a dependency on something you shouldn't need to care about.
  • inject dependencies, in order to avoid implicit dependencies to specific constructors of specific types

OTHER TIPS

Measuring coupling is hard.

Simplistic metrics like number of inter-class references are easy to compute, but don't actually tell you much that's useful about the code.

There are multiple factors that tell if coupling is bad. The most important are:

  • the extent to which the class that references another depends on details of that class
  • the extent to which the coupled-to class is likely to change
  • the extent to which coupled classes are independent in purpose; classes that are likely to be modified together aren't as much of a problem I'd they're coupled as random unrelated class.

Note that these are essentially impossible to quantify. So never trust a numeric metric of coupling, because it ignores these critical factors.

Note that the first is likely to be much worse in a class that inherits from another than one that use composition, if only because inheritance provides a more convenient mechanism so is likely to be used more. It also often provides methods of interacting at a more privileged level (ie via protected members). Both tend to increase bad types of coupling. Favouring composition therefore helps avoid bad coupling.

Other techniques that help include following the open closed principle (where doing so doesn't lead to monstrously bad designs), which tends to reduce the second point in my list, and following the single responsibility principle which tends to improve the third.

Licensed under: CC-BY-SA with attribution
scroll top