4
\$\begingroup\$

Lets say I have a key and door. My third class (player) needs to pick up a key and open the doors. How should those objects communicate without making too much dependencies between them?

\$\endgroup\$
3
  • \$\begingroup\$ what exactly do you mean by dependencies? You should be able to easily create an inventory system for the player (list that stores objects that extend an item interface) for holding objects like a key. As for a door, you will need someway to tell how far the player is from the door and then check the inventory for the proper key object that can open it. \$\endgroup\$ May 9, 2013 at 23:21
  • \$\begingroup\$ I mean class dependencies. Like that it's not good when object(A) knows too much about the object(B). \$\endgroup\$
    – Tom
    May 9, 2013 at 23:25
  • \$\begingroup\$ Well they are always going to have to know something about each other. For example when your player hits the action button while facing a door there needs to be someway to identify it can be used (even if it's just implementing an interface) the door will also need a way to check and see if the person using it has a key. So there really is no way to separate them completely. \$\endgroup\$ May 9, 2013 at 23:34

2 Answers 2

6
\$\begingroup\$

Precise answer usually (or always?) depends on the specific situation and circumstances but I think it's a good idea to try to model the real-world relations between objects.

Like in your example - the human is the only entity that actually does something (takes action). So probably this class should call key and door's methods. Key doesn't have to know or do anything. It only has to have some kind of ID (to check if that's the right one). The door has to know what key fits into its lock (have the key's ID). Nothing else. Well, it can also have some kind of Open() method (to allow player to pass through it, but that's a different thing, actually). The human takes the actions (take/produce a key, put it in the door's lock and try to open the door).

Modeling the real-world relations between objects is good... because it's proven to work! It works in real-life so it should work in your application, too (provided it's not too complex/impossible to implement).

Also, as always, try to keep things as simple as possible and use common sense - if your app or the situation your trying to implement is small/simple - it's sometimes just better to do it the easiest way you can think of without overthinking and overdesigning objects' relationships - because there's no point in it.

\$\endgroup\$
7
  • \$\begingroup\$ Would it be right to directly call those methods in user interface class? \$\endgroup\$
    – Tom
    May 10, 2013 at 0:18
  • \$\begingroup\$ What user interface class? \$\endgroup\$
    – NPS
    May 10, 2013 at 0:20
  • \$\begingroup\$ I have a class where I check what button player clicked, what keyboard or mouse button pressed. So would it be right to directly call entity methods from user interface class or I should have some kind of controller class for controlling user interaction with game logic? \$\endgroup\$
    – Tom
    May 10, 2013 at 0:30
  • 3
    \$\begingroup\$ -1 for "Modeling the real-world relations between objects is good" yikes. \$\endgroup\$ May 10, 2013 at 7:24
  • 1
    \$\begingroup\$ It's just very, very rarely even close to good advice. It might work sometimes, this being an example of it being okay, but usually the way good OOP design interacts and how real-life objects interact are quite dissimilar. Much of the bad code I've dealt with over the years is from junior developers trying to model objects in a computer program after their physical counterparts; think about data and logic flow, not how real-life works. If they come out being similar, cool coincidence. \$\endgroup\$ May 10, 2013 at 17:08
3
\$\begingroup\$

The simplest way to enforce a relationship without strong coupling is to use a Mediator. There could be an Unlocker system that keeps track of the player's keys and listens to collision messages between the player and doors. By moving this dependent logic upwards, you keep the player, the key, and the door decoupled.

Here's some C# code to illustrate. If you need clarification just leave a comment.

class Unlocker
{
    public OnCollision(Entity a, Entity b)
    {
        TestCollision(a, b);
        TestCollision(b, a);
    }

    private void TestCollision(Entity a, Entity b)
    {
        if(a is Player)
        {
            if(b is Key)
            {
                b.Destroy();
                _keys++;
            }

            if(b is Door && _keys > 0)
            {
                b.Destroy();
                _keys--;
            }
        }
    }

    private int _keys;
}

In this example, OnCollision is registered to the collision system, which activates it (and the other collision handlers) when two entities collide.

As you can see, this simple Unlocker class added a new set of behaviors dependent on the player, keys, and doors without creating any coupling between the entities themselves. This is especially important for object models like composition where entities are not able to implement their own behaviors.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I would probably rework this function, that OnCollision call at the end going to get called every time leading to a stack overflow. \$\endgroup\$ May 10, 2013 at 16:33
  • \$\begingroup\$ You're right. I completely overlooked that. \$\endgroup\$
    – jmegaffin
    May 10, 2013 at 19:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .