简体   繁体   中英

Instantiating a child class that extends an abstract class, the abstract class having a parameter pointing to another different abstract class

I am working on a project for my Object Orientated Java II course, and I am having trouble with starting it, as I can't seem to follow the logic of how the abstract classes I have to override with my own concrete classes are constructed (without running into a StackOverflowError). I am not allowed to declare any new state information in my concrete classes or modify the given abstract classes.

Here is the code for the abstract "Game" class:

public abstract class Game
{
    protected Board board;           // the board for this game
    protected Player p1;             // the game's first player 
    protected Player p2;             // the game's other player
    protected Player winner;         // the game's winner
    protected int score1;            // p1's score
    protected int score2;            // p2's score
    protected Player currentPlayer;  // the player whose turn it is to play 

    /**
     * Constructor for objects of class Game
     * 
     * @param board   an empty, game-specific board to play the 
     *                game on
     */
    public Game(Board board)
    {
        this.board = board;
        board.setGame( this );
        score1 = score2 = 0;
    }// constructor

    /**
     *  Plays an entire game
     */
    public void play()
    {
        setUp();
        board.display();
        while (! gameOver() )
        {
            p1.playAMove();
            board.display();
            if (gameOver())
                break;
            p2.playAMove(); 
            board.display();
        }// main game loop
        wrapUp();
    }// play method

    /**
     * Sets up the board in its initial configuration as well as
     * the two players of this game
     */
    public abstract void setUp();

    /**
     *  Determines whether or not the game has ended
     */
    public abstract boolean gameOver();

    /**
     * Finishes the game after a tie or a win
     */
    public abstract void wrapUp();

}

Here is the code for the abstract "Board" class:

public abstract class Board
{
    protected Game game;        // the game using this board
    protected Piece[][] board;  // the state of the board
    protected int rows;         // the vertical size of the board
    protected int cols;         // the horizontal size of the board

    /**
     * Constructor for objects of class Board
     * 
     * @param  game       game the board is used for
     * @param  numRows    number of rows of the board
     * @param  numColumns number of columns of the board
     */
    public Board(Game game, int numRows, int numColumns)
    {
        this.game = game;
        rows = numRows;
        cols = numColumns;
        board = new Piece[rows][cols];
    }// constructor

    /**
     * Associates to this board the game that uses it
     *
     * @param  game  the game that uses this board
     */
    public void setGame(Game game)
    {
        this.game = game;
    }// setGame method

    /**
     *  Returns the piece located at the given position or null
     *  if no piece is at that location; throws an exception if 
     *  the location is off the board
     *
     * @param  row     the row index of the location
     * @param  column  the column index of the location
     * @return         the piece at the given location or null
     *                 if the location is empty
     */
    protected Piece getPiece(int row, int column)
                      throws InvalidBoardPositionException
    {
        if (row < 0 || row >= rows || column < 0 || column >= cols)
            throw new InvalidBoardPositionException(row,column);

        return board[row][column];
    }// getPiece method

    /**
     *  Puts down the given piece at the given location; throws an 
     *  exception if the location is off the board or already
     *  occupied
     *
     * @param  piece   the piece to place on the board
     * @param  row     the row index of the target location
     * @param  column  the column index of the target location
     */
    protected void putPiece(Piece piece, int row, int column)
                 throws InvalidBoardPositionException
    {
        if ( row < 0 || row >= rows || 
             column < 0 || column >= cols ||
             ! isEmpty(row,column) )
            throw new InvalidBoardPositionException(row,column);

        board[row][column] = piece;
    }// putPiece method

    /**
     *  Removes from the board the piece at the given location; 
     *  throws an exception if the location is off the board or empty
     *
     * @param  row     the row index of the target location
     * @param  column  the column index of the target location
     */
    protected void removePiece(int row, int column)
           throws InvalidBoardPositionException
    {
        if ( row < 0 || row >= rows || 
             column < 0 || column >= cols ||
             isEmpty(row,column) )
            throw new InvalidBoardPositionException(row,column);

        board[row][column] = null;
    }// removePiece method
    
    /**
     *   Returns true if and only if the specified location is
     *   empty
     *   
     *   @param   row    row index of the location being checked
     *   @param   col    column index of the location being checked
     *   @return         true if and only if there is no piece at
     *                   the location being checked
     */
    protected boolean isEmpty(int row, int col)
    {
        return board[row][col] == null;
    }// isEmpty method

    /**
     * Displays the board on the terminal window
     */
    protected abstract void display();

}

I have to extend both classes (GGame extends Game, GBoard extends Board), and use this code in GGame to start the program:

public static void newGame()
{
    new GGame().play();
}

There are other classes, but all I care about for now is actually getting the program to create an instance of "GGame" so I can move forward. I've tried doing this:

/**
 * Constructor
 */
public GGame()   //needs to have no parameters
{
    super(new GBoard());
}

However, the constructor of the abstract "Board" class (which "GBoard" has to extend) requires an instance of "Game" to be passed to it. But if I pass an instance of "GGame" into the "GBoard" constructor it loops infinitely as new GGame() and new GBoard() call each other.

I'll take any ideas about what I can do, and will provide more info if necessary. I don't want someone to do the project for me, I'm just legitimately stuck and don't know how to proceed. I'm sure I'm missing something.

If you don't want to modify the implementation of abstract classes, you must pass null to the constructor of the superclass as follows:

class BoardImpl extends Board {
    BoardImpl() {
        super(null, a, b);
    }
}

class GameImpl extends Game {
    GameImpl(Board board) {
        super(board);
    }
}

and then pass the Board instance to the Game constructor:

Board board = new BoardImpl();
Game game = new GameImpl(board);

also note that passing this in the class constructor like this:

public Game(Board board)
{
    this.board = board;
    board.setGame( this );
    score1 = score2 = 0;
}

is a very bad practice because at the time of passing this instance is not yet fully constructed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM