18

I'm designing a text-based adventure game for a school progress. I have each "level" set up as a class, and each explorable area (node) as a method within the appropriate class.

What's messing with me is the code to move from one node to another. Because each node is connected to up to four other nodes, I have to repeat an extremely similar block of code in each method.

What I'd prefer to do is include an array of methods at the beginning of each node, like this:

public static void zero()
{
    ... adjacentNodes[] = {one(), two(), three(), four()};
}

And then send that array to a generic method, and have it send the player to the right node:

public static void move(...[] adjacentNodes, int index)
{
    adjacentNodes[index];
}

I simplified my code, but that's the general idea. Is this possible?

1
  • 1
    What are the method signatures of one(), two() etc? Commented Nov 26, 2010 at 6:50

7 Answers 7

61

Whenever you think of pointer-to-function, you translate to Java by using the Adapter pattern (or a variation). It would be something like this:

public class Node {
    ...
    public void goNorth() { ... }
    public void goSouth() { ... }
    public void goEast() { ... }
    public void goWest() { ... }

    interface MoveAction {
        void move();
    }

    private MoveAction[] moveActions = new MoveAction[] {
        new MoveAction() { public void move() { goNorth(); } },
        new MoveAction() { public void move() { goSouth(); } },
        new MoveAction() { public void move() { goEast(); } },
        new MoveAction() { public void move() { goWest(); } },
    };

    public void move(int index) {
        moveActions[index].move();
    }
}
3
  • 1
    Okay, I'm going to give this a try. Thanks for the suggestion! Commented Nov 26, 2010 at 3:58
  • 5
    Note that this example creates 4 MoveActions per Node instance. By rethinking this implementation a bit you could make MoveAction objects sharable for all instances. In this case, it would involve changing move() to move(Node), implement the 4 MoveAction as static classes, and passing this in the call to move().
    – gpeche
    Commented Nov 26, 2010 at 18:45
  • Thank you so much, helped a lot ! Commented Jul 12, 2017 at 17:39
6

Just have your nodes be objects that all adhere to the same interface, then you'll be able to call their methods reliably.

5

Since Java does not have the concept of methods as first-class entities, this is only possible using reflection, which is painful and error-prone.

The best approximation would probably be to have the levels as enums with a per-instance implementation of a method:

public enum Level1 implements Explorable{
    ROOM1 {
        public void explore() {
            // fight monster
        }
    }, ROOM2 {
        public void explore() {
            // solve riddle
        }
    }, ROOM3 {
        public void explore() {
            // rescue maiden
        }
    };

}

public interface Explorable{
    public abstract void explore();    
}

public static void move(Explorable[] adjacentNodes, int index)
{
    adjacentNodes[index].explore();
}

However, this is a bit of an abuse of the enum concept. I wouldn't use it for a serious project.

1
  • Still, I'll give it a try. Thanks for the tip! Commented Nov 26, 2010 at 3:59
2

Your design has fundamental flaws. Normal OO design would have each "level" be an object (of Class 'level' or something like it). each 'explorable area' would also be an object, contained within the level object - maybe of class ExplorableArea. The 'explorable areas' can be different kinds, in which case you make them different subclasses of ExplorableArea.

1
  • You're right; it isn't the best structure I could have come up with. I'm in the middle of a re-design, but I wanted to get this problem sorted out first Commented Nov 26, 2010 at 3:56
0

Try thinking about solutions without reflection. It's can be enums, for example.

0

I arrive late at the party with one possible approach, now you can use java.util.function (link) for this kind of problem.

To literally answer the question, regardless of its correctness, or applicability, here a possible version:

public static void zero()
{
    Function<World, World> one = (World start) -> RoomWithMonster.in(start);
    Function<World, World> two = (World start) -> EmptyRoom.in(start);
    Function<World, World> three = (World start) -> RoomWithMonster.in(start);
    Function<World, World> four = (World start) -> Treasure.in(start);

    List<Function<World, World>> adjacentNodes = List.of(one, two, three, four);
    return adjacentNodes;
}


public static void move(List<Function<World, World>> possibleNodes, int index)
{
    World beginning = World.start();
    World end = possibleNodes.get(index).apply(beginning);
}

This approach prefer immutability and add a little World class to abstract away the state of the game but still maintaining the question you wanted.

NB: fortunately now the reflection comments are obsolete!

-5

You can use Reflection class to create an array of methods. http://java.sun.com/developer/technicalArticles/ALT/Reflection/

1
  • 11
    No, don't do it. It is just bad programming practice to replace OO design with reflection. Commented Nov 25, 2010 at 20:53

Not the answer you're looking for? Browse other questions tagged or ask your own question.