I'm practicing Java by making a program that can play some online puzzle games such as minesweeper, chess, etc. Since the games are all played on an orthogonal grid, I found the methods common to each game and tossed them in a class that has a 2-d array of elements I named Orthogonals. My first intuition was to let the squares of the board be generically typed:
public abstract class GridBoard <E extends Orthogonal>{
private final E[][] board;
public final int width;
public final int height;
public GridBoard(int width, int height){
this.width=width;
this.height=height;
board= new E[][]();
}
/*...*/
}
Unfortunately, new E[][]()
isn't possible for some important reasons. I would be happy using a constructor like public GridBoard(E[][] board)
, but I want Orthogonal
to have methods like orthogonal.getNeighbor(NORTH)
, which require them to know which (final
) board they're a part of. From what I can tell, there are a few different ways of getting around this limitation, but none of them feel like they simplify the design. My goal is to let MinesweeperBoard
s work with a MineSquare[][]
, but ChessBoards
have ChessSquare[][]
, for example.
https://stackoverflow.com/a/18111163/8611351 shows how an array can be created, but the class of a generic can't be obtained dynamically. A class would have to be passed into the constructor, which adds needless complexity for the implementer.
Some answers to questions about similar patterns suggest letting the subclass of GameBoard
fill the array with their own type of squares, and then casting each time the board is read from. Is this an acceptable practice? When are casting and instanceof
considered acceptable design?
board
doesn't need to be defined in the abstract class, and all of the methods in Orthogonal
can rely on the concrete implementations. But that sounds like a great way to put repetitive code into every different game.
I could remove the Orthogonal
class entirely and put the logic for navigating the board into GridBoard
. But if I do that, there won't be as clean a way to write something like return square.neighbors().filter(MineSquare::isBomb).count()
.
I could change the class definition to GridBoard <E>
and make Orthogonals a class that get created as needed and read E
s from the board. This seems like the most reasonable solution, but I'm very curious about the best way to solve the array of subclasses problem if that wasn't an option. Is there a perk or drawback that I've overlooked?
>` instead of an array?
– shmosel Nov 19 '17 at 04:27