Composition and Loose Coupling

Doesn’t the composition approach lead to a lot of loose coupling, since all the components need to know a lot about the other components for them all to work well together? I’m not sure how to build a system that is component based that doesn’t have a lot of loose coupling.

Hi,

Welcome to our community! :slight_smile:

In which course and lecture are you?

Only if you code it that way.

The more coupling you have, the more people tend to move away from loose coupling and towards tight coupling. It does depend on how it’s executed.

A quote from Stack overflow that might help:

Loose coupling is a method of interconnecting the components in a system or network so that those components, depend on each other to the least extent practically possible…

Low coupling suggest that class should have least possible dependencies. Also, dependencies that must exist should be weak dependencies - prefer dependency on interface rather than dependency on concrete class, or prefer composition over inheritance .

1 Like

Hi, I’m in the “Programming Design Patterns For Unity” course.

Loose coupling is preferred, especially over tight coupling. It’s impossible (well, possible, but generally fruitless) to eliminate coupling altogether. Components do need to work together to accomplish goals.

The composition approach in and of itself won’t determine how loosely or tightly coupled your classes are, but how those classes interact and depend on each other will.

Unfortunately, some things in Unity are already tightly coupled, and these are just things we have to live with… For example:
A GameObject must have a Transform. Without a Transform, a GameObject is meaningless. Similarly, a Transform must be placed on a GameObject. These two things cannot exist independent of one another. Add to that that these two classes actually reference each other. The relationship between a GameObject and a Transform can be seen as tightly coupled. Technically, all of our classes (MonoBehaviours) are fairly tightly coupled to GameObjects and Transforms as well. Still Unity’s component system is a great example of a composition pattern. Classes are added to the GameObject as building blocks to get specific behaviours.

While we can’t help the tight coupling between a MonoBehaviour and a GameObject/Transform, we can control how tightly coupled our classes are to each other…

A great example of this is found in the RPG courses. We have two classes that perform specific actions… The Mover, which moves your character to a given point, and a Fighter, which attacks other characters. As it turns out, in our game design, if the Fighter isn’t close enough to attack, then it directs the Mover component to move the character until it’s close enough and then it attacks.

If the player controller detects a new input, either the Fighter or the Mover is sent an instruction to begin an action… At first, we then instruct the other component to cancel itself… quite literally

GetComponent<Mover>().Cancel();

or

GetComponent<Fighter>().Cancel();

This creates a tight coupling between the two classes. The Fighter component needs the Mover component to function (it does this no matter what in our game), and the Mover component needs the Fighter component so that it can cancel.

As we add more action type components, this relationship can get very tangled, very quickly… An ObjectCollector class might need to cancel Fighter and Mover… Add in a Shopper class that needs to cancel Mover, ObjectCollector, and Fighter… It stacks up quickly, and very soon you can find all of these classes tightly coupled and a tangled mess.

To fix this, we reduce coupling through an Interface, in this case, an IAction interface with a single method

void Cancel()

Then we have an Action Scheduler that lets any action notify the ActionScheduler that it is the current Action, and then whatever the old current action is will be automatically Cancelled().
Just like that, none of these classes needs to know about the others (well, except Mover, as they all use Mover).

That example aside, the key is to use as few references as possible between classes. Avoid any direct references to variables in favor of Getxxxx and Properties. Avoid cross dependencies (A relies on B, but B relies on A). Whenever possible, abstract away explicit class references in favor of Interfaces. For example, in the above classes, Fighter currently depends on Mover so that it can move the character… but what if there were another way to move than the one used by Mover… perhaps a Teleporter or a flying movement… rather than Fighter trying to account for all of these things, you could have an IMoveCharacters interface with a

void MoveTo(Vector3 destination)

As we compose the classes for the character, you would put whichever IMoveCharacters class you wished on the GameObject and the Fighter would automagically find the right one, with no real knowledge as to how the character is moved from point A to point B. It doesn’t need that information, just that you want to move.

I hope that made some semblance of sense.

1 Like

Thank you. I think I understand. I may have to read that again a few times :sweat_smile:

Perhaps the RPG course would be worth checking out too. Often I find it difficult to scale up these ideas given in small examples to larger projects.

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.

Privacy & Terms