Advertisement

understanding couplig

Started by September 08, 2024 01:18 AM
2 comments, last by scott8 3 months, 1 week ago

I don't have a very strong grasp of coupling, but I understand that it refers to something that has a high amount of dependencies, but I don't exactly know what that looks so it's hard to point out what the dependencies are or if they even are any. I believe a basic example of coupling would this:

class ObjectB {
public:
	Object() : objectA(...) {}
private:
	ObjectA objectA;
};

ObjectB is dependent on ObjectA if I were to change the constructor or something I would then need to update ObjectB and I believe I can improve this through methods like dependency injection although I'm not entirely sure how that helps since wouldn't it still depend on the class meaning changes made would still require changes in the other? Here is an example from my own project and I'm curious if this also counts as coupling? if so how?

enum class EditorAction {
	ADD_SCRIPT,
	ADD_PART,
	ADD_MODEL,
	NONE
};

void Editor::update(Scene& scene) {
	if (m_editorContext.action == EditorAction::ADD_SCRIPT) {

	}
	else if (m_editorContext.action == EditorAction::ADD_PART) {

	}
	else if (m_editorContext.action == EditorAction::ADD_MODEL) {

	}
}

None

I'm not entirely sure how that helps since wouldn't it still depend on the class meaning changes made would still require changes in the other?

Generally you can use an interface, also called an abstract base class in C++.

If the interface doesn't change it doesn't matter what the final implementation does. Take a pointer to the interface, and use the pointer to the interface to use the object. Then you can create as many other concrete types as you want and replace it as you want by providing a pointer to an instance. This is how many systems like GameObject or Component or Behavior classes work. You can use any objects that implement the interface, and call any functions provided by the interface.

Another thing I see is your big list of if(action==x) commands. This pattern of an interface works here, too. You can have a pointer to an action command interface and a function like DoAction that will do whatever it does. This moves the logic to the commands and away from the editor. It can be a built-in type like a std::function if you don't want to specifically make a specific interface for it. Then any new system can assign their new commands and they will be automatically used by the editor without changing editor code. You will only need to change command code.

That big list of commands is a great example of problematic coupling. You can build up a huge list of commands due to that coupling. As a somewhat extreme example, you might have something like: Person->GetPet()->GetTail()->GetTailBone()->PlayWagAnimation(), you've coupled all the systems together that a person has a dog and the dog has a tail and the tail gets wagged. In contrast Person->DoPetAnimation() doesn't require any of that knowledge, and allows you to modify the behavior on a per-object basis. You can do an appropriate animation for any pet regardless of it is a dog, cat, dragon, or unicorn, or the case of no pet at all. More specifically to your editor, instead of having the editor code manipulate all the inner workings of other objects, you would issue an action command on the object and let the object manipulate itself.

Advertisement

Consider a collision detection system (CDS). The CDS determines if the player was hit by a bullet, and then takes action if true.

Tightly coupled: The CDS will subtract 10 heath from the player. Unless the player is wearing armor, then subtract 5. Also, If the player has the relection spell active, all the potential damage gets reflected back to who ever fired the bullet, and the player takes NO damage. If the player's health drops below 0%, the player should die and the game should end.

The above example is tightly coupled because the CDS has to know about the player, all the armor they're wearing, all the spells they have active, anything that could effect what happens, etc. If you change the armor attributes, or add different armor or spells, you have to update the CDS to handle it.

Lightly coupled: The CDS sends a message to the player, saying they were hit bu a bullet fired by a GameActor object.

The above is lightly coupled because the CDS doesn't know anything about the player, their armor, active spells, etc. Upon receiving the message, the player object will have to update its own health, and maybe set update bPlayerDead=true to stop the game if it drops below 0%. I can change all kinds of things about the player, it won't affect my CDS, making life alot easier!

This topic is closed to new replies.

Advertisement