4

Imagine there was a GameState type which uses a GameContext (via a process method):

abstract class GameState {
    public abstract void process(GameContext context);
}

GameContext would contain things such as the Player, Shops, ect.. things that are essential to the game.

A state would access what it needed:

class CombatState extends GameState {
    public void process(GameContext context) {
        Player player = context.getPlayer();

        if(player.isAlive()) {
            //...
        }
    }
}

The statement player.isAlive() could be rewritten as context.getPlayer().isAlive().

My Question

The Law of Demeter states that objects should only interact with direct relatives. Would this be a violation of the principle, and how would it be resolved?

For each state to be handled dynamically, the formal parameters must be acceptable by all possible states. This makes it hard to pass the object strictly what it needs, which is why each state grabs what it needs from a "main source". I feel that main source has very low cohesion, since a ShopState would require different data than a CombatState

Vince
  • 14,470
  • 7
  • 39
  • 84

2 Answers2

5

A State is not a Process, a Process is a Process. To fight is a process, to be alive is a state.

Using the abstract name of process makes you need to break the Demeter's law.

Look this example:

class CombatProcess extends GameProcess {
    public void hit(Player puncher, Player beaten) {
        if (beaten.getState().isAlive()) {
           Weapon oneWeapon = one.getCurrentWeapon();
               ...
        }
    }
}

Everything in CombatProcess is as concrete as it could.

To analyze what player fights against what player is NOT the responsibility of the CombatProcess itself! Before the CombatProcess starts you must know who you fight against.

EDIT:

In the comments of this answer you wrote:

If I had the states in a Set, List or Map, I would not be able to polymorphically process the states,

This is absolutly correct. The Hook/Anchor-Pattern is from 1996 and still used widely and glory in windows (so called system-hooks). Unfortunately It did not find his way to the top 10 patterns of OOD because of a few critics. One of this critic is :

... its not easy to abstract all the operations of a process into logical independent hooks, and to thereafter anchor them and iterate them properly.

My private opinion is that the Hook/Ancher-Pattern was revolutionary in 1996 and will be revolutionary in the combination with the CDI (spring in example) in the future.

Finally! You could decide:

  1. Break the Law of Demeter.
  2. Drop the Hook/Ancher-Pattern.
  3. Write a workaround described here.
Grim
  • 1,938
  • 10
  • 56
  • 123
  • 2
    Love how you cut straight down to the naming problem. Beautiful example why naming things is one of the two hard problems in computer science. – mabi Dec 09 '15 at 09:38
  • I've already mentioned changing the formal parameters of `GameState#process(GameContext)`: "*For each state to be handled dynamically, the formal parameters must be acceptable by all possible states. This makes it hard to pass the object strictly what it needs, which is why each state grabs what it needs from a "main source"*" - If I had the states in a `Set`, `List` or `Map`, I would not be able to polymorphically process the states, since each state has a different requirement. – Vince Dec 09 '15 at 11:40
  • In your method, you have `oneWeapon = one.getCurrentWeapon()`. What if I were to make a call such as `oneWeapon.doSomething()`? It would be the same as `one.getCurrentWeapon().doSomething()`, violating the principle, wouldn't it? – Vince Dec 09 '15 at 11:42
  • I also do not see `State#process` as being any kind of bad naming convention. `GameState` could implement some kind of `Processable`, which would make it justifiable. A state needs to be processed in *some* way. Doing it in the way you suggested (changing the formal parameters) would introduce a lot more management, since every state would need to be explicitly handled by some container (in order to pass in the correct parameter values). If there were 5000 states, some kind of `StateTransitionTable` would get out of hand – Vince Dec 09 '15 at 12:13
  • Peter Rader what would be your solution in this case: http://stackoverflow.com/q/37916206/6053907 ? – Gam Jun 24 '16 at 11:45
  • @Phantom I added a comment. Try to concretize the question please. – Grim Jun 25 '16 at 07:08
0

Since Law of Delimiter is a specific case of Loose Coupling.

The way i think it works is:

We can access fields of a particular class and its methods even though we are chaining multiple methods(say). We do it all the time in java, the thing to note is that, chaining is only applied for methods of a single class.

Delimiter's law cautions us from accessing objects and/or methods of multiple classes at once.

Example:

if we have classes A, B, C.

B class has a field holding a reference of A, and C has reference of B.

Then we should not fetch reference of A through C by using getters, it helps in maintaining Loose Coupling.

Again, this is the way i think it works.

Sarthak Mittal
  • 5,794
  • 2
  • 24
  • 44
  • What do you mean by "*chaining is only applied for methods of in a single class*"? Are you saying chaining is acceptable if it occurs from the same instance, such as `context.getPlayer().doSomething()`? If so, that's actually what the law of demeter is put in place to avoid. That would be interacting with the `Player` instance contained in `GameContext` (an indirect relative) rather than interacting with only `GameContext`. It would be nice to pass in `Player` rather than `GameContext`, but that would mean every state would require it's own unique formal parameters – Vince Dec 09 '15 at 08:02
  • @VinceEmigh no you are getting it wrong, what i m suggesting is: suppose you have a String reference 's', then s.replaceFirst().replaceAll() is valid (because the reference and methods belong to the same class) – Sarthak Mittal Dec 09 '15 at 08:47
  • Move the question to programmers.stackexchange.com and you will become all my upvotes and i have no :D. – Grim Dec 09 '15 at 10:48
  • @PeterRader your answer did explain an important concept of OOP, but not the Delimiter's law, although, i believe that my upvote was not in vain. ;) – Sarthak Mittal Dec 09 '15 at 11:03