首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >战舰游戏终端游戏

战舰游戏终端游戏
EN

Code Review用户
提问于 2017-05-23 19:02:22
回答 1查看 499关注 0票数 3

我是Java新手,我想学习和改进。

整个项目可以是在此视察

这是一个终端游戏“战舰”:电脑将船只随机设置在海洋上,你必须击落所有这些船只。

我有几个问题:

  1. 我尽量遵循最佳实践,依赖注入,尽可能。但我不确定我的方法是否好。例如,在OceanImpl.java中,我创建了类,这些类的参数本身都是海洋脉冲-cass本身。这种依赖注入实现正确吗?如果没有,你会怎么做?
  2. 我试着使类不大于100行,因此我尽可能多地导出到分离的小类和函数中,以便干燥,创建可重用的组件。但对于一些课程,我认为它仍然不够干燥。例如,SetOnOceanVerticallySetOnOceanHorizontally非常相似。是否有可能进一步重构它们?
  3. 尽管我使用了接口来使程序尽可能灵活地适应变化,但我认为它仍然不够灵活。Game.java的Lookint,特别是行int[] userInput = Helper.getIntegerUserInputInRange(ocean.getXLength(), ocean.getYLength());,如果我想从命令行UI切换到GUI,或者从2D切换到3D,那么我至少也要写这一行。因此,我不能只是交换UI,并期望不要触及代码的其他部分。

Main.java

代码语言:javascript
复制
package main;

import main.controller.Game;
import main.model.MaritimeElement;
import main.model.OceanImpl;

public class Main {
    public static void main(String[] args) throws Exception {
        Ocean ocean = new OceanImpl(6, 7);

        ocean.setShipWhereThereIsPlace(MaritimeElement.AIRCRAFT_CARRIER);
        ocean.setShipWhereThereIsPlace(MaritimeElement.AIRCRAFT_CARRIER);
        ocean.setShipWhereThereIsPlace(MaritimeElement.CRUISER);
        ocean.setShipWhereThereIsPlace(MaritimeElement.CRUISER);
        ocean.setShipWhereThereIsPlace(MaritimeElement.DESTROYER);
        ocean.setShipWhereThereIsPlace(MaritimeElement.DESTROYER);

        Game game = new Game(ocean);
        game.start();
    }
}

OceanImpl.java

代码语言:javascript
复制
package main.model;

import main.controller.*;
import main.controller.assertion.AssertionMaritime;
import main.controller.assertion.AssertionMaritimeImpl;
import main.controller.utils.Helper;

import java.awt.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class OceanImpl implements Ocean{
    MaritimeElement[][] ocean;
    Map<Point, MaritimeElement> shotsMade = new HashMap<>();
    Set<Point> shipsPlaced = new HashSet<>();
    RandomCoordinateFactory randomCoordinateFactory;
    FindFreePosition findFreePosition;
    AssertionMaritime assertShip = new AssertionMaritimeImpl();
    SetOnOcean setOnOceanHorizontally;
    SetOnOcean setOnOceanVertically;
    SetOnOcean[] setOnOcean;

    public OceanImpl(int xLength, int yLength) throws Exception {
        assertShip.isLargerThanMinimumDimension(xLength, yLength);
        ocean = Helper.initOcean(yLength, xLength);

        randomCoordinateFactory = new RandomCoordinateFactory(ocean[0].length, ocean.length);
        findFreePosition = new FindFreePosition(this, assertShip);
        setOnOceanHorizontally = new SetOnOceanHorizontally(this);
        setOnOceanVertically = new SetOnOceanVertically(this);
        setOnOcean = new SetOnOcean[]{setOnOceanHorizontally, setOnOceanVertically};
    }
    @Override
    public int getXLength() {return ocean[0].length;}
    @Override
    public int getYLength() {return ocean.length;}
    @Override
    public MaritimeElement getLocationStatusAt(int x, int y) {return ocean[y][x];}
    @Override
    public MaritimeElement shootAt(int[] userInput) throws Exception {
        int x = userInput[0], y = userInput[1];
        assertShip.isPointWithinRange(x,y, this.getXLength(), this.getYLength());
        shotsMade.put(new Point(x,y), getLocationStatusAt(x,y));
        shipsPlaced.remove(new Point(x,y));
        return getLocationStatusAt(x,y);
    }
    @Override
    public int howManyTargetsHit() {return shipsPlaced.size();}
    @Override
    public MaritimeElement getShotMade(int x, int y) {return shotsMade.get(new Point(x,y));}
    @Override
    public Result setShipWhereThereIsPlace(MaritimeElement ship) throws Exception {
        int[] position = findFreePosition.getPosition(ship.val());
        if (position[Coordinate.X.val()] != -1){
            setOnOcean[position[Coordinate.ORIENTATION.val()]]
                .setShip(position[Coordinate.X.val()],position[Coordinate.Y.val()],ship);
            return Result.SUCCESS;
        }
        return Result.FAILED;
    }
    @Override
    public void setMaritime(int x, int y, MaritimeElement ship) {
        try {
            ocean[y][x] = ship;
        } catch(Exception e) {
            e.getCause();
        }
    }
    @Override
    public void setShipsPlaced(int x, int y) {
        shipsPlaced.add(new Point(x, y));
    }
}

Game.java

代码语言:javascript
复制
package main.controller;

import main.controller.assertion.AssertionMaritime;
import main.controller.assertion.AssertionMaritimeImpl;
import main.controller.utils.Helper;
import main.model.Ocean;
import main.model.OceanImpl;
import main.model.MaritimeElement;
import main.view.CommandLineInterface;
import main.view.UserInterface;

public class Game {
    Ocean ocean;
    UserInterface ui = new CommandLineInterface();
    AssertionMaritime assertUser = new AssertionMaritimeImpl();
    public Game(OceanImpl ocean) {
        this.ocean = ocean;
    }

    public void start() throws Exception {
        do {
            ui.showOceanHidden(ocean);
            int[] userInput = Helper.getIntegerUserInputInRange(ocean.getXLength(), ocean.getYLength());
            MaritimeElement shotAtElement = ocean.shootAt(userInput);
            displayResult(shotAtElement);
        } while(ocean.howManyTargetsHit() != 0);
        ui.displayFeedbackWin();
        ui.showOcean(ocean);
    }

    private void displayResult(MaritimeElement shotAtElement) {
        if (assertUser.isWater(shotAtElement)) {
            ui.displayFeedbackShotMissed();
        } else {
            ui.displayFeedbackShotHit();
        }
    }
}

SetOnOceanHorizontally.java

代码语言:javascript
复制
package main.controller;

import main.model.MaritimeElement;
import main.model.Ocean;

public class SetOnOceanHorizontally implements SetOnOcean {
    Ocean ocean;
    public SetOnOceanHorizontally(Ocean ocean) {
        this.ocean = ocean;
    }

    @Override
    public void setShip(int x, int y, MaritimeElement ship) {
        for (int i = 0; i < ship.val(); i++) {
            int xCoordinate = x + i, yCoordinate = y;
            try {
                ocean.setMaritime(xCoordinate, yCoordinate, ship);
            } catch(Exception e) {
                e.getCause();
            }
            ocean.setShipsPlaced(xCoordinate,yCoordinate);

        }
    }
}

SetOnOceanVertically.java

代码语言:javascript
复制
package main.controller;

import main.model.MaritimeElement;
import main.model.Ocean;

public class SetOnOceanVertically implements SetOnOcean {
    Ocean ocean;
    public SetOnOceanVertically(Ocean ocean) {
        this.ocean = ocean;
    }
    @Override
    public void setShip(int x, int y, MaritimeElement ship) {
        for (int i = 0; i < ship.val(); i++) {
            int xCoordinate = x, yCoordinate = y + i;
            try {
                ocean.setMaritime(xCoordinate,yCoordinate, ship);
            } catch(Exception e) {
                e.getCause();
            }
            ocean.setShipsPlaced(xCoordinate,yCoordinate);
        }

    }
}

RandomCoordinateFactory.java

代码语言:javascript
复制
package main.controller;

import java.awt.*;

public class RandomCoordinateFactory {
    private int xLength;
    private int yLength;

    public RandomCoordinateFactory(int xLength, int yLength) {
        this.xLength = xLength;
        this.yLength = yLength;
    }
    private int getRandomHorizontalXPosition(int shipLength) { return (int)Math.floor(Math.random() * (xLength - shipLength));}
    private int getRandomHorizontalYPosition() {
        return (int)Math.floor(Math.random() * yLength);
    }
    private int getRandomVerticalXPosition() {
        return (int)Math.floor(Math.random() * xLength);
    }
    private int getRandomVerticalYPosition(int shipLength) {return (int)Math.floor(Math.random() * (yLength - shipLength));}
    public Point getStartPointForHorizontalShip(int shipLength) {
        return new Point(getRandomHorizontalXPosition(shipLength), getRandomHorizontalYPosition());
    }
    public Point getStartPointForVerticalShip(int shipLength) {
        return new Point(getRandomVerticalXPosition(), getRandomVerticalYPosition(shipLength));
    }
}

FindFreePosition.java

代码语言:javascript
复制
package main.controller;

import main.controller.assertion.AssertionMaritime;
import main.model.MaritimeElement;
import main.model.Ocean;
import main.model.Orientation;

import java.awt.*;

public class FindFreePosition {
    Ocean ocean;
    RandomCoordinateFactory randomPoint;
    AssertionMaritime assertShip;
    public FindFreePosition(Ocean ocean, AssertionMaritime assertShip) {
        this.ocean = ocean;
        this.assertShip = assertShip;
        randomPoint = new RandomCoordinateFactory(ocean.getXLength(), ocean.getYLength());
    }

    public int[] getPosition(int shipLength) throws Exception {
        int[][] startingPoints = findFreePositionsHorizontallyAndVertically(shipLength);
        int selectRandomly = (int)(Math.random() * startingPoints.length);
        if (startingPoints[selectRandomly][0] != -1) return startingPoints[selectRandomly];

        throw new Exception("No space for ships found");
    }
    private int[][] findFreePositionsHorizontallyAndVertically(int shipLength) throws Exception {
        Point startPointHorizontalShip = randomPoint.getStartPointForHorizontalShip(shipLength);
        Point startPointVerticalShip = randomPoint.getStartPointForVerticalShip(shipLength);
        int[] coordHorizontal = findFreePositionHorizontally(shipLength, startPointHorizontalShip.x, startPointHorizontalShip.y);
        int[] coordVertical = findFreePositionVertically(shipLength, startPointVerticalShip.x, startPointVerticalShip.y);

        return new int[][]{coordHorizontal, coordVertical};
    }

    private int[] findFreePositionVertically(int shipLength, int xOffset, int yOffset) throws Exception {
        int x = xOffset,y = yOffset, k = 0, xIteration = 0;
        int[] start = {-1,-1,Orientation.VERTICAL.getValue()};

        while (x < ocean.getXLength() && xIteration < 2) {
            while (y < ocean.getYLength()) {
                MaritimeElement currentMaritimeElement = ocean.getLocationStatusAt(x,y);
                if (k == 0) start = new int[]{x, y, Orientation.VERTICAL.getValue()};
                if (assertShip.isWater(currentMaritimeElement)) k++;
                if (k == shipLength) return start;
                if (assertShip.isSpaceAvailable(currentMaritimeElement, ocean.getYLength(), shipLength, y, k)) {
                    k = 0;
                    start = new int[]{-1, -1, Orientation.VERTICAL.getValue()};
                }
                y++;
            }
            y = 0;
            k = 0;
            x++;
            if (x >= ocean.getXLength()) xIteration++;
            x = x % ocean.getXLength();
        }
        return start;
    }

    private int[] findFreePositionHorizontally(int shipLength, int xOffset, int yOffset) throws Exception {
        int x = xOffset, y = yOffset, k = 0, yIteration = 0;;
        int[] start = {-1,-1, Orientation.HORIZONTAL.getValue()};

        while (y < ocean.getYLength() && yIteration < 2) {
            while (x < ocean.getXLength()) {
                MaritimeElement currentMaritimeElement = ocean.getLocationStatusAt(x,y);
                if (k == 0) start = new int[]{x, y, Orientation.HORIZONTAL.getValue()};
                if (assertShip.isWater(currentMaritimeElement)) k++;
                if (k == shipLength) return start;
                if (assertShip.isSpaceAvailable(currentMaritimeElement, ocean.getXLength(), shipLength, x, k)) {
                    k = 0;
                    start = new int[]{-1, -1, Orientation.HORIZONTAL.getValue()};
                }
                x++;
            }
            x = 0;
            k = 0;
            y++;
            if (y >= ocean.getYLength()) yIteration++;
            y = y % ocean.getYLength();
        }
        return start;
    }
}

CommandLindInterface.java

代码语言:javascript
复制
package main.view;

import main.controller.DrawMaritime;
import main.controller.DrawMaritimeImpl;
import main.model.MaritimeElement;
import main.model.Ocean;

public class CommandLineInterface implements UserInterface{

    DrawMaritime drawMaritime = new DrawMaritimeImpl();
    @Override
    public void display(String message) {
        System.out.println(message);
    }
    @Override
    public void displayFeedbackWin() {
        display("You won!");
    }
    @Override
    public void displayFeedbackShotMissed() {
        display("Missed");
    }
    @Override
    public void displayFeedbackShotHit() {
        display("Hit");
    }
    @Override
    public void showOceanOpen(Ocean ocean) {
        genericDrawOcean(ocean, drawShipsOpenly);
    }
    @Override
    public void showOcean(Ocean ocean) {
        genericDrawOcean(ocean, drawAllShips);
    }
    @Override
    public void showOceanHidden(Ocean ocean) {
        genericDrawOcean(ocean, drawShotsMade);
    }

    private void genericDrawOcean(Ocean ocean, DrawStuffOnOcean drawStuffOnOcean) {
        for (int y = 0; y < ocean.getYLength(); y++) {
            for (int x = 0; x < ocean.getXLength(); x++) {
                if (y == 0 && x == 0) {
                    System.out.print("\t");
                    for (int i = 0; i < ocean.getXLength(); i++) {
                        System.out.print(i + "\t");
                    }
                    System.out.println();
                }
                if (x == 0) System.out.print(y + "\t");
                drawStuffOnOcean.draw(ocean, y, x);
            }
            System.out.println();
        }
    }

    interface DrawStuffOnOcean{
        void draw(Ocean ocean, int y, int x);
    }

    DrawStuffOnOcean drawShipsOpenly = (Ocean ocean, int y, int x) -> {
        MaritimeElement element = ocean.getLocationStatusAt(x,y);
        if(element == MaritimeElement.WATER) {
            drawMaritime.water();
        } else if (element == MaritimeElement.DESTROYER) {
            drawMaritime.destroyer();
        } else if (element == MaritimeElement.CRUISER) {
            drawMaritime.cruiser();
        } else if (element == MaritimeElement.AIRCRAFT_CARRIER) {
            drawMaritime.aircraftCarrier();
        }
    };

    DrawStuffOnOcean drawAllShips = (Ocean ocean, int y, int x) -> {
        MaritimeElement element = ocean.getLocationStatusAt(x,y);
        MaritimeElement checkForShotsMade = ocean.getShotMade(x,y);
        if (checkForShotsMade == null) {
            drawMaritime.water();
        } else {
            if(element == MaritimeElement.WATER) {
                drawMaritime.missShip();
            } else if (element == MaritimeElement.DESTROYER) {
                drawMaritime.destroyer();
            } else if (element == MaritimeElement.CRUISER) {
                drawMaritime.cruiser();
            } else if (element == MaritimeElement.AIRCRAFT_CARRIER) {
                drawMaritime.aircraftCarrier();
            }
        }
    };

    DrawStuffOnOcean drawShotsMade = (Ocean ocean, int y, int x) -> {
        MaritimeElement element;
        if (ocean.getShotMade(x,y) == null) {
            drawMaritime.water();
        } else {
            element = ocean.getShotMade(x,y);
            if(element == MaritimeElement.WATER) {
                drawMaritime.missShip();
            } else {
                drawMaritime.hitShip();
            }
        }
    };
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2017-05-23 20:43:35

提示:

  • 文件!和一个README
  • 以后尽量避免以Set开头的类名,以避免设置者从setSet开始,这会伤害眼睛。这不值得重构。
  • 有些字段,如Game.ocean,没有封装。
  • catch(异常e) { e.getCause();}没有任何效果,很可能在开发周期结束时导致无用的An error occured消息。如果您没有传递一个异常,但是您需要处理它,抛出一个RuntimeException,或者通知像sentry.io这样的在线服务。try-catch(Exception)几乎从不正确..。
  • 您的项目没有pom.xml,但是在.idea中有与IDE相关的文件。我会提供一个基于命令行的跨平台、跨IDE构建命令,以便让其他人尽可能容易地构建和运行您的项目。

你的问题:

  1. 在您的代码中没有看到依赖项注入。为它使用一个遵循Java规范的FLOSS框架,这就是它存在的原因。
  2. 公共抽象类SetOnOceanBase实现SetOnOcean {.私有最终布尔值水平;//仅公开给子类的构造函数@重写公共空setShip(int,int,MaritimeElement ship)抛出SpecificException { for (int i= 0;i< ship.val();i++) {if(水平){.ocean.setMaritime(xCoordinate,yCoordinate,ship);ocean.setShipsPlaced(xCoordinate,yCoordinate);}
  3. 抽象接口是很好的,但是如果您所接触的任何东西,您都会很快进入YAGNI逻辑,特别是当涉及到数据容器(粗略地说不应该实现接口)时,所以如果您能在5秒内想到接口的用例,那么就可以使用它--我的经验法则是在没有技术规范和复杂的类图的情况下进行业余项目。稍后,在任何现代IDE中,一个接口的提取只需单击一两次。
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/164048

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档