I am trying to do the design of a Bejeweled game. I have basically 3 classes. The Game
class, which is what is going to be used by the player, a Board
class, that represents the board, and a SwitchController
class that is responsible for checking if the wanted switch on the board is valid, making the switch, counting the number of possible switches available (so I can know when the game is over, etc).
My current design is something like the following:
Game:
isGameOver()
isSwitchValid(coord1, coord2)
makeSwitch(coord1, coord2)
getPieceAt(coord)
getBoardLength()
IBoard:
getPieceAt(coord)
setPieceAt(coord, piece)
getLength()
My idea would then to have a ISwitchController
:
ISwitchController:
isSwitchValid(coord1, coord2)
makeSwitch(coord1, coord2)
getAllValidSwitches()
Here is a little diagram of how the classes are to be organized:
I would have 2 different concrete classes of IBoard
available for use (and for each one of them, I'd have to have an ISwitchController
implementation).
My program is to have 2 IBoard implementations:
The first, ArrayBoard
, will have all the pieces of the board stored in a 2D Array. There is nothing special about it. I will define an ArrayBoardSwitchController
for managing this class.
The second, ListBoard
, will have for each color of pieces, a List/Set with all the coordinates of the pieces of that color. I will define a ListBoardSwitchController
for managing this class.
The main issue here is that the implementation of SwitchController
will be totally different on ArrayBoard
and on ListBoard
. For example, while for implementing getAllValidSwitches()
ArrayBoardSwitchController
only needs the getPieceAt()
method, that would not be a good idea to do with ListBoardSwitchController
(in that class I use internally lists because it's easier to check if the move is valid that way).
From what I can see, there are 2 different possible solutions:
I could either merge together the
ISwitchController
and IBoard
interfaces. That way I'd only have
two classes, Game and Board (while
basically Game would just be a
controller for the Board, as it
would be the Board that had all the
game logic). It wouldn't be that nice
because the classes wouldn't be
as cohese as they could be if I had
3 distinct classes.
Let the interfaces as they are and put
all the methods I need to work with public
in the concrete classes. For example, if I need
a getYellowPiecesList()
method, I'd put it public
on ListBoard
so ListBoardSwitchController
could
use it. ListBoardSwitchController
would only
know about it because it knows it only works
against ListBoards
.
What's your opinion on the matter? The focus here is not so much on how to design the Bejeweled game, but how to solve this problem, that is recurrent when you try to implement algorithms: on one hand you want to have a clear and good OOP design, and in the other sometimes that gets in the way of having a sound and effective algorithm implementation.
The main issue here is that the implementation of SwitchController will be totally different on ArrayBoard and on ListBoard.
If this is the case, then it sounds like you haven't designed the IBoard
interface well enough so that classes can use an implementation of IBoard
without knowing the implementation details. If the user of an IBoard
needs to know what implementation is being used, then it almost defeats the purpose of having an interface!
I would strongly suggest re-visiting the methods you are exposing on IBoard
to see if there is a way you can expose something like "get the piece at this coordinate" in a more generic way. Make sure that any methods a controller needs to invoke on a IBoard
instance are only the methods in the IBoard
interface.
For example, while for implementing getAllValidSwitches() ArrayBoardSwitchController only needs the getPieceAt() method, that would not be a good idea to do with ListBoardSwitchController(in that class I use internally lists because it's easier to check if the move is valid that way).
If an operation such as "get piece at this coordinate" is instrumental to the IBoard
interface, then the implementations must be faithful to their contract and implement it correctly. It sounds as if your ListBoard
is not faithfully meeting the contract set out in IBoard
.
3: Let ArrayBoardSwitchController and ListBoardSwitchController be inner classes of ArrayBoard and ListBoard. The implementation of the controller is tied to the implementation of your board, thus it makes sense to keep them together. Because the controller will be an inner class you can use the implementation details from the board. Then to make it work extend the IBoard interface to return a ISwitchController.
Note that this is only slightly different from option 1. (The ISwitchController can now be used indirectly from a IBoard, merging them gives direct access to ISwitchController)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With