Karel J Robot Strategies and Decorators

This exercise will require building a set of classes in separate files, within a visible package, say, package karel. It will define infrastructure to make it easy to incorporate strategies into robot programs. These classes won't be robots, but can be used by robots and are often features (fields) of robot classes. Strategies and Decorators are discussed in Chapter 4, including how to build up a list of decorators to "remember" a chain of actions for execution later.

The first file contains only an interface:

package karel;

import kareltherobot.UrRobot;

public interface UrRobotStrategy {
    public void doIt(UrRobot robot);
}

Strategies "execute" via their doIt method applied to a robot. Initially we will restrict it to actions avaiable to all UrRobots, but it can be extended later.

This simplest strategy does nothing when invoked. It is often how we start a chain of decorators.

package karel;

import kareltherobot.UrRobot;

public class NullStrategy implements UrRobotStrategy {

    @Override
    public void doIt(UrRobot robot) {
        // Nothing
    }

    public UrRobotStrategy decorated() {
        return this;
    }

}

Decorator is an abstract class that isn't instantiated, since it, too, does nothing. It is the concrete subclasses that hold robot actions.

package karel;

public abstract class Decorator extends NullStrategy {
    private UrRobotStrategy decorated;

    public Decorator(UrRobotStrategy strategy) {
        decorated = strategy;
    }

    public UrRobotStrategy decorated() {
        return decorated;
    }
}

What we want to build is a set of decorator classes, each of which only performs a single simple UrRobot action that might be useful in several contexts. For example:

package karel;

import kareltherobot.UrRobot;

public class MoveDecorator extends Decorator {

    public MoveDecorator(UrRobotStrategy strategy) {
        super(strategy);
    }

    @Override
    public void doIt(UrRobot robot) {
        robot.move();
        decorated().doIt(robot);
    }
}

We will also want similar decorators for other common actions: TurnLeftDecorator, TurnRightDecorator, TurnAroundDecorator, PickBeeperDecorator, PutBeeperDecorator, MoveDecorator and possibly one or two others. The author hasn't found any use for a TurnOffDecorator, however, but it is easy to build.

Note that the MoveDecorator sends the move message to its argument, a robot, prior to invoking the doIt method of the decorated strategy. This implies that if you build up a chain of decorators the last one added will be the first one that acts.