Is it a code smell for objects to contain information regarding the context in which they're used?

Viewed 131

Lets say I'm making a game with a bunch of levels, whereby as you progress through levels, new types of enemies are introduced. If a developer has an enemy and wants to get the level an enemy can be found in, the most intuitive way I can think of allowing them to do this would be to store a list levels on the enemy that they are contained within. This however I feel like is a problem, because now I've coupled my enemy and my level together. My enemy now knows about the context in which it used. My research says that these kinds of relationships are unhealthy for maintaining software, but it seems intuitive to use from a level above.

Here's a very basic implementation:

public class Level
{
    List<Enemy> typesOfEnemies;
    public Level(List<Enemy> typesOfEnemies)
    {
        this.typesOfEnemies = new List<Enemy>(typesOfEnemies);

        for (int i = 0; i < typesOfEnemies.Count; i++)
        {
            typesOfEnemies[i].AddLevelContainedWithin(this);
        }
    }
}

public class Enemy
{
    public List<Level> levelsContainedWithin = new List<Level>();
    public void AddLevelContainedWithin(Level level)
    {
        levelsContainedWithin.Add(level);
    }
}

So there's probably a few problems associated with this code. The most obvious one that sticks out to me is that I can add a level to an enemy without updating my Level's types of enemies which puts them out of sync. I could resolve this by creating another class that does the work, ensuring the Level and Enemy stay in-sync, but now I've added a layer of code complexity. The developer now has another class they have to know about to work with.

My question is, how do I make this maintainable and intuitive to for a developer to use?

1 Answers

You can introduce another class that does the coupling:

class LevelManager
{
    public List<Enemy> GetEnemies(Level l) { ... }
    public List<Level> GetLevels(Enemy e) { ... }
}

Now all your data-objects have to know is the LevelManager.

Actually it´s not even neccessary to have this dependcy in neither your Enemy- nor your Level-class. If a developer wants to know in which levels an enemy can spawn, he may use the LevelManager instead.

Related