The main purpose of this lab is to let you work with one or two other lab partners to get started on programming project #4. Most of the effort should be spent on writing the code for IRequestor in the given GameModel class. IRequestor is an example of what is called the facade design pattern.
You are allowed to work in teams of two or three during the lab session and share the code with your lab partners. Do feel free to share your lab code with your lab partners. After the lab session, you are to take your lab code and work alone (or with your own team) to complete programming project #4.
When a player wants to put his/her game piece at some position on the board, it needs a way to communicate to
To avoid such complicated maneuvering, the player simply talks to an interface called IRequestor passing it the appropriate information and let this requester do the rest of the work internally. In the design pattern language, IRequestor plays the role of a "facade".
Here are some relevant excerpts of code that illustrate how the player interacts with the IRequestor .
/** * This class represents an abstract player of the game. * The players are represented as a circular linked list. */ public abstract class APlayer { private IRequestor iRequestor; private int player; private APlayer nextPlayer = this; /** * The constructor for the class. * @param iRequestor The requestor that the player uses to request moves of the board. * @param player The player number of this player. */ public APlayer(IRequestor iRequestor, int player) { this.iRequestor = iRequestor; this.player = player; } /** * Tells this player to take its turn. */ public abstract void takeTurn(); /** * other methods elided... */ } /* * This class represents a concrete computer player. */ public class ComputerPlayer extends APlayer { private INextMoveStrategy iNextMoveStrategy; private IModel model; /** * The constructor for the class. * @param iRequestor The requestor that this player will use to communicate with the model. * @param player This player's player number. * @param model A reference to the IModel. Needed to call the getNextMove() method * of the INextMoveStrategy. * @param iNextMoveStrategy The strategy used to calculate this player's next movfe. */ public ComputerPlayer(IRequestor iRequestor, int player, IModel model, INextMoveStrategy iNextMoveStrategy) { super(iRequestor, player); this.model = model; this.iNextMoveStrategy = iNextMoveStrategy; System.out.println("ComputerPlayer is using "+iNextMoveStrategy); } /** * Used by the TurnControl to tell this player to take its turn. * When the computer takes its turn, it will calculate its next move and * then request that move of the model. * If the computer makes and invalid move, the computer will print an error * message to the screen and the it will take its turn again. */ public void takeTurn() { System.out.print("Computer player "+ getPlayer() +" ("+ this +") takes turn..."); final Point p = iNextMoveStrategy.getNextMove(model, getPlayer()); System.out.println("and moves to "+ p); getRequestor().setTokenAt (p.y, p.x, getPlayer(), new IRejectCommand() { // ANONYMOUS COMMAND! public void execute() { System.out.println("ComputerPlayer: The move at ("+p.x+", "+p.y+") is invalid."); takeTurn(); } }); } }
When a player is instantiated, it is given an IRequestor to communicate with the model. As shown in ComputerPlayer.takeTurn(), the computer player gets the best next move from the next move strategy and then asks the requestor (getRequestor()) to set the game token at the best move's position, passing to the requestor an anonymous IRejectCommand, in case the move is illegal. This situation may happen if the next move strategy is a totally random move.
The IRejectCommand has only one method called execute()
/** * A basic command that is executed when a move request has been rejected by the model. */ public interface IRejectCommand { /** * This method is called by the model when a move is rejected. */ public abstract void execute(); } The IRequestor has only one method called setTokenAt(...)
/** * This interface encapsulates the request mechanism used by an APlayer to try * to make a move to a given (row, col) by a given player. * This is the public (client) end of a "Facade" design pattern that hides the * internal workings of the model. */ public interface IRequestor { /** * Requests to the model that a given player's token be placed on the * internal board at (row, col). * An IRejectCommand is supplied that should be executed if the request is rejected. */ public abstract void setTokenAt(int row, int col, int player, IRejectCommand rejectCommand); }
A player gets its requestor at construction time. Who creates the concrete requestor and passes it to the player? The GameModel via its getPlayers() method! The GameModel has access to the board model, the turn control manager, and the view administrator. By creating an IRequestor as an anonymous inner class, the GameModel can thus set up the appropriate context for a player to make a request for a move without knowing anything about the board, the view, and the turn control!
In this lab you are to work with others to try to implement the IRequestor anonymous inner class that is stubbed out the GameModel code. Go to programming project #4 and review the directions there.