HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

OOP Battleship implementation in Java - part 2

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
partjavabattleshipimplementationoop

Problem

Previous review can be found here

I got so many great tips on how to improve, so I've written a new version while trying to implement all the different suggestions.

So once again, any insight with regards to clean code, best practices etc. would be greatly appreciated.

Board.java

package com.tn.board;

import com.tn.field.IGameField;
import com.tn.field.WaterField;
import com.tn.ship.Ship;
import com.tn.field.ShipField;
import com.tn.ship.ShipSize;

import java.awt.*;
import java.util.Scanner;

public class Board {
    private static final char WATER = '~';
    private static final int BOARD_SIZE = 10;
    private static final char[] BOARD_LETTERS = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
    private static final String HORIZONTAL = "H";
    private static final String VERTICAL = "V";

    private Scanner scanner;
    private IGameField[][] board;
    private static final Ship[] ships;

    static {
        ships = new Ship[] {
                new Ship("Carrier", ShipSize.CARRIER),
                new Ship("Battleship", ShipSize.BATTLESHIP),
                new Ship("Cruiser", ShipSize.CRUISER),
                new Ship("Submarine", ShipSize.SUBMARINE),
                new Ship("Destroyer", ShipSize.DESTROYER)
        };
    }

    public Board() {
        this.scanner = new Scanner(System.in);
        this.board = new IGameField[BOARD_SIZE][BOARD_SIZE];
        for(int i = 0; i = 0
                && y = 0;
    }
}


IGameField.java

package com.tn.field;

import com.tn.game.Result;

public interface IGameField {
    char getIcon();
    Result shootAt();
}


ShipField.java

```
package com.tn.field;

import com.tn.game.Result;
import com.tn.ship.Ship;

public class ShipField implements IGameField {
private final Ship ship;

public ShipField(Ship ship) {
this.ship = ship;
}

@Override
public char getIcon() {
char icon;
Result shipState = ship.getState();
switch (shipState) {

Solution

-
If you want to make public static constants use interface.

public interface Constants {
    final String SIZE = 5;
}


-
What is the purpose of the Board class? It seems like a global controller for the whole game process. Those validations strive to be moved into some validator class (CollisionValidator or CollisionManager is the common class in the most games). I mean your Board class is doing drawing, validation and storing game-world objects at once. Pretty big and difficult to extend class.

-
ShipSize is a redundant class (not to say it should be an enum). You use its values only in one place - at the static initializer. You can either move ships names and their sizes to some sort of Ships enum or use integers constants directly at your static initializer.

public enum Ships {
    CARRIER("Carrier", 5),
    BATTLESHIP("Battleship", 4),
    CRUISER("Cruiser", 3),
    SUBMARINE("Submarine", 3),
    DESTROYER("Destroyer", 2);

    private String name;
    private int size;

    Ships(String name, int size) {
        this.name = name;
        this.size = size;
    }
}


-
Also every model you have can draw, which neglects separation of concerns. It can be hard to debug such things and can become pretty complicated. Always is a good idea to create a printer class which only can use System.out.print, where all methods take entities with their values to print (entities ideally should not say how to print themselves).

Code Snippets

public interface Constants {
    final String SIZE = 5;
}
public enum Ships {
    CARRIER("Carrier", 5),
    BATTLESHIP("Battleship", 4),
    CRUISER("Cruiser", 3),
    SUBMARINE("Submarine", 3),
    DESTROYER("Destroyer", 2);

    private String name;
    private int size;

    Ships(String name, int size) {
        this.name = name;
        this.size = size;
    }
}

Context

StackExchange Code Review Q#162174, answer score: 2

Revisions (0)

No revisions yet.