开发者

Advise requested regarding proper use of encapsulation in Java

开发者 https://www.devze.com 2023-01-11 22:40 出处:网络
I\'m creating a little puzzle game just as a hobby project but the project has now reached a point that there is quite a lot of code (about 1500 lines). Although I\'ve tried to prevent it, the code ha

I'm creating a little puzzle game just as a hobby project but the project has now reached a point that there is quite a lot of code (about 1500 lines). Although I've tried to prevent it, the code has become messy. I definitely want to clean up the code and make it more maintainable and readable while I still can.

There are 3 classes handling actions regarding puzzle pieces in my game:

class PieceController{
    private arrayOfPieces;
    private selectedPiece;
    //actions like select a piece, dropa piece
}

class Piece{
    private pieceID
    private ArrayOfPieceStates
    //handles the initial creation of pieceStates and returns the current state
}

class PieceState{
    private stateDimensions
    // the particular rotation of a piece, aware of it's dimensions.
}

Propbably this structure should be redesigned as a whole but let's assume that it's ok for just now.

The problem: There also is a JPanel that takes care of the graphics and it needs to be aware of the PieceState of the current puzzle piece to draw it. the drawing method of the panel then gets the dimensions with a request like:

PuzzleController.getPiece().getState().getDimensions() 

This seems like bad practice as it breaks encapsulation totally as I've learned now. When I would deside to redesign the puzzle piece structure these chains of getters will break;

Then I thought I might follow the "Tell don't ask" principle for the drawing:

PieceController.drawPiece(drawingInfo) // called by the graphics Panel
Piece.drawPiece(drawingInfo) // called by PieceController
PieceState.drawState(drawingInfo) // called by Piece, now here we are aware of piece dimensions so drawing can take place.

(not that drawingInfo in the acutal code is a line of arguments that the drawing methods require.)

In some way I've implemented encapsulation as the first drawPiece method is all the graphic panel needs and it doesn't need to worry about how the pieces are further structured. But now it feels like I've only reversed the information dependency and haven't made much progress.

first it was: Drawing method needs the dimension information of current puzzlePiece's state to draw. now it has become: puzzlePiece's state needs information about the graphical environment to perform drawing o开发者_如何学JAVAperations (where on the screen to draw the piece for example).

now when the drawing method of PieceState requires additional of different input and the declaration of this method changes (it might require more information for example) the calls to the drawing methods have to change all the way 'up'.

Conclusion and actual question So basically the problem is: old situation violated encapsulation, new situation might not but also doesn't seem like a solid implementation of the encapsulation principle. so my question is: what are your ideas to improve this design? How would you implement Puzzle pieces, their states and drawing operation on them?


Build a PieceDrawer that knows how to draw a Piece. I strongly suggest the following separation:

  • Model classes: keep and allow access and modification of internal application state, but know nothing whatsoever of how they are going to be manipulated or represented. Your Piece / PieceContoller / PuzzleController classes should fall in here. As far as I can see, PieceState should be merged into Piece (as it will no longer contain that much data). Your PuzzleController will now only know how to modify model class state, but nothing about user input.
  • View+Controller classes: strictly for UI. Access the model through the model's high-level methods, but delegate as much as possible about the actual game to the model. Your PieceDrawer and GamePanel (a JPanel) classes would fall in this category. The GamePanel will be responsible for gathering user input and executing the moves in the PuzzleController, and then painting each piece with the PieceDrawer.

The only ugly point with this setup is the coupling between PieceDrawer and Pieces. On the other hand, you have all that coupling in a single place, and piece-painting is likely to be similar for all pieces. By replacing the GamePanel and the PieceDrawer, you could convert your whole application to text-based, without touching any model classes. Or offer users a choice of piece representations (make PieceDrawer an interface, have several classes implementing them)...


PieceState should probably be an inner class of Piece. DrawPiece can then use the PieceState to determine who to draw itself.

0

精彩评论

暂无评论...
验证码 换一张
取 消