tags:

views:

211

answers:

4

Here's a snippet of code:

    //Game board is made up of Squares.  A player can place GamePieces on a Square.
    public class CheckersBoard
    {
        public boolean PlaceGamePiece(GamePiece gamePiece, int nRow, int nColumn) {
            return m_theGameBoard[nRow][nColumn].PlaceGamePiece(gamePiece);
        }

        private Square[][] m_theGameBoard;
    }

Let say I'm testing the PlaceGamePiece method (using junit) and I need to access the m_theGameBoard so I can look at it and verify the GamePiece was placed on the correct Square and has the correct data.

In C++ I'd either make the test class a friend so it can access the private member m_theGameBoard, or I'd have a function that returns a const GameBoard that cannot be modified (because it's const):

const GameBoard& GetGameBoard() const { return m_theGameBoard; }

Now I can do what ever checking I want to do on the game board, but I can't modify the game board because it's const.

Java doesn't support returning const references or friend classes. So my question is what is the standard Java way of doing this?? Do I have to just provide a bunch of get accessors that allow me check the data on the Square?

UPDATE: I ended up writing a GetPiece method as Kaleb Brasee suggested.

public GamePiece GetGamePiece(Point pt) {
    return new GamePiece(m_theGameBoard[pt.GetRow()][pt.GetColumn()]);
}

Notice I create a new GamePiece object and return that. I'm not returning the GameBoards internal reference, therefore no one can modify the gameboard because they only have a copy! Nice! Thanks for the help guys, some really good advice.

FYI: I keep changing the names of the objects when I post them on here, sorry if that confused anyone.

A: 

Yes - your choices basically boil down to either having

Square getSquareAtLocation(int row, int col) { ... };

or using one of the Java collections which you could then pass through Collections.unmodifiableList(...)

(note that if you used a multidimensional List, you'd have to be careful to wrap the inner Lists as well to make sure they're not modifiable either)

If this is only ever going to be used for testing, you could also create a function that returns a deep copy of the array.

Steven Schlansker
A: 

Apply the principle of Tell, Don't Ask.

Example

Consider:

public class Board {
  private Piece[][] board;

  public Board() {
  }

  public void put( Piece piece, int x, int y ) {
    Piece[][] board = getBoard();
    board[x][y] = piece;
  }

  public void remove( int x, int y ) {
    put( null, x, y );
  }

  public boolean hasPiece( PieceType pieceType, int x, int y ) {
    Piece[][] board = getBoard();
    Piece piece = board[x][y];

    return piece != null && piece.isType( pieceType );
  }

  private Piece[][] getBoard() {
    return this.board;
  }
}

Unit Testing

Unit testing then takes very little effort:

public class Test {
  public static void main( String args[] ) {
    Board board = new Board();
    board.put( new KnightPiece(), 5, 5 );

    assertTrue( board.hasPiece( KnightPieceType, 5, 5 ) );
  }
}

Detailed Example

Review an API for a Go game board for details.

Dave Jarvis
How is it functional?
jalf
Because you are "getting" a piece of data from another object and doing something with it. This is how C and C structures work (you pass in a data structure to a function). OO is about asking an object to do something with the data it encapsulates. Read the "Tell, Don't Ask" article for a thorough explanation.
Dave Jarvis
For the down-votes, please note why this is an incorrect answer. Thank you!
Dave Jarvis
Would you happen to mean "procedural" instead of "functional"?
Éric Malenfant
@Dave: That is procedural, not functional. And C is not a functional language. There's a huge difference. Functional programming is at least as high-level, elegant and expressive as OOP (I'd say much more so). Procedural is the old messy C-style. Anyway, removing my downvote now that the "functional" reference has been edited out. :)
jalf
+2  A: 

You could define the variable as protected, so that if the unit test is in the same package, it can access it.

However, I would just add a public method getPiece(int row, int col) that returns the piece on that square (or null if there's no piece there). It's likely you'll need a method like that anyway, and you could use it in your tests.

Kaleb Brasee
I'm under the impression that protected is the same thing as c's friend.
Karl
But what if a class working with board needs to display all the pieces on the board (such as a GUI class that needs to display all pieces on the board) -- how would you go about that without a method to get pieces? In my chess app I have a `Board.pieceOn(Square)` method that returns a Piece if any Piece is present, or null if the Square's empty. Would returning a map of occupied Squares mapped to Pieces be any better?
Kaleb Brasee
@Kaleb: http://www.javaworld.com/javaworld/jw-01-2004/jw-0102-toolbox.html Why not have the objects, given a graphics context, draw themselves? Add a `draw` method to the pieces (or a subclass of each piece, if you prefer to keep the UI code separate). I think `board.draw( graphics )` and `piece.draw( graphics )` makes perfect sense. Combine this with Holub's technique outlined in the link and you have a good solution that avoids breaking encapsulation.
Dave Jarvis
+1  A: 

The default access modifier for a method or property is "package-protected", which means "visible only within my package". Therefore, you can emulate the semantics of "friendship", while maintaining a separate code base for tests, by having two distinct source folders, but with the same package structure.

src
|--com
    |
    --cchampion
         |
         --MyClass.java
tests
|--com
    |
    --cchampion
         |
         --TestMyClass.java

Then, within MyClass.java

public class MyClass {
    private int nonTestedThing;
    int[][] testedThing;  // this is visible to TestMyClass
    // or
    // protected int[][] testedThing;
    // if you want it visible to kids
}

Not ideal in any respect, but it's one way to go about it.

Jonathan Feinberg