I have a tic-tac-toe game and there is a class in it that describes the game from beginning to end. I think it is too big, but I do not like I can not decide what to take from there, for which I will not undertake and there is a reason why it should be here.

// описываСт ΠΏΠ°Ρ€Ρ‚ΠΈΡŽ public class Game implements Play { // ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π½ΠΎΠ³ΠΎ класса Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ вынСсСна ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° наличия побСдитСля private Validation validation = new ValidationWinnerUtil(); // ΠΈΠ³Ρ€ΠΎΠΊΠΈ private Subject[] gamers = new Subject[2]; // Π²Π²ΠΎΠ΄ с консоли private Input input; // ΠΏΠΎΠ±Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ Π΄Π°Π½Π½ΠΎΠΉ ΠΏΠ°Ρ€Ρ‚ΠΈΠΈ private Subject win; // доска для ΠΈΠ³Ρ€Ρ‹ private Desk board; public Game(Input input) { this.input = input; } // устанавливаСт Ρ€Π°Π·ΠΌΠ΅Ρ€ доски private void initBoard() { System.out.println("Π₯ΠΎΡ‚ΠΈΡ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ стандартный Ρ€Π°Π·ΠΌΠ΅Ρ€ доски 3Ρ…3 (y/n)?"); String answer = this.input.getString(); if (answer.equals("n")) { System.out.println("Π’Π²Π΅Π΄ΠΈΡ‚Π΅ Ρ€Π°Π·ΠΌΠ΅Ρ€ доски :"); this.board = new Board(this.input.getNumber()); } else if (answer.equals("y")) { this.board = new Board(3); } else { initBoard(); } } // for test Subject[] getGamers() { return gamers; } // for test Desk getBoard() { return board; } // ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ массив с ΠΈΠ³Ρ€ΠΎΠΊΠ°ΠΌΠΈ. порядок мСняСтся Π² зависимости ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ ΠΊΡ‚ΠΎ // Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ. ΠΊΡ‚ΠΎ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Ρ‚ΠΎΡ‚ ΠΈΠ³Ρ€Π°Π΅Ρ‚ крСстиками. @Override public void choiceSide() { System.out.println("ΠšΡ‚ΠΎ Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ: (Bot / I) :"); String answer = this.input.getString().toLowerCase(); if (answer.equals("i")) { this.gamers[0] = new User(Cell.X, "user"); this.gamers[1] = new User(Cell.O, "bot"); } else if (answer.equals("bot")){ this.gamers[0] = new User(Cell.X, "bot"); this.gamers[1] = new User(Cell.O, "user"); } else { choiceSide(); } } // Π·Π°Ρ†ΠΈΠΊΠ»ΠΈΠ²Π°Π΅Ρ‚ ΠΎΡ‡Π΅Ρ€Π΅Π΄Π½ΠΎΡΡ‚ΡŒ Ρ…ΠΎΠ΄ΠΎΠ² ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² @Override public void loopMove() { this.initBoard(); PrinterBoard.printDesc(board.getBoard()); while (validation.gameCanGoOn(board.getBoard())) { for (Subject subject : this.gamers) { try { if (validation.gameCanGoOn(board.getBoard()) ) { board.move(subject.getColor(), getNewPosition(subject)); PrinterBoard.printDesc(board.getBoard()); this.win = subject; } } catch (IllegalMove illegalMove) { illegalMove.printStackTrace(); } } } } // Π΄Π°Π΅Ρ‚ Π½ΠΎΠ²ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ для Ρ…ΠΎΠ΄Π° Ссли Π±ΠΎΡ‚ Ρ‚ΠΎ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ Π² классС AutomaticMove // Ссли ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Ρ‚ΠΎ с консоли ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ private Position getNewPosition(Subject subject) { if (subject.getName().equals("user")) { System.out.println("По Π²Π΅Ρ€Ρ‚ΠΈΠΊΠ°Π»ΠΈ:"); int y = this.input.getNumber(); System.out.println("По Π³ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚Π°Π»ΠΈ:"); return new Position(this.input.getNumber(), y); } else { return new AutomaticMove().generateMove(this.board); } } // Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ ΠΊΠΎΠ³Π΄Π° ΠΈΠ³Ρ€Π° ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Ρ‚ΡŒΡΡ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ смотрит Π΅ΡΡ‚ΡŒ Π»ΠΈ ΠΏΠΎΠ±Π΅Π΄ΠΈΡ‚Π΅Π»ΡŒ Ссли Π΄Π° Ρ‚ΠΎ записываСт Π΅Π³ΠΎ Π² ΠΏΠΎΠ»Π΅ win @Override public Subject initWinner() { if (!this.validation.emptyCellExist(board.getBoard()) && !this.validation.winnerDetermines(board.getBoard())) { System.out.println("ΠΠΈΡ‡ΡŒΡ"); return new User(Cell.EMPTY, "nobody"); } else { System.out.println(format("ΠŸΠΎΠ±Π΅Π΄ΠΈΡ‚Π΅Π»ΡŒ: %s", this.win.getColor())); return this.win; } } } Π’ΠΎΡ‚ тСсты ΠΊ Π½Π΅ΠΌΡƒ: @Test public void whenUserMoveFirstThenUserAddInArrGamersFirst() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"i"}); input.setAnswersNum(new int[]{3}); Game game = new Game(input); game.choiceSide(); assertThat(game.getGamers()[0].getName(), is("user")); assertThat(game.getGamers()[1].getName(), is("bot")); } @Test public void whenBotMoveFirstThenUserAddInArrFirst() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"bot"}); input.setAnswersNum(new int[] {3}); Game game = new Game(input); game.choiceSide(); assertThat(game.getGamers()[0].getName(), is("bot")); assertThat(game.getGamers()[1].getName(), is("user")); } @Test public void whenBotMoveFirstAndWinByHorizontalThen() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"bot", "y"}); input.setAnswersNum(new int[] {2, 0, 2, 1}); Game game = new Game(input); game.choiceSide(); game.loopMove(); Subject subject = game.initWinner(); assertThat(subject.getName(), is("bot")); assertThat(subject.getColor(), is(Cell.X)); } @Test public void whenManMoveFirstAndWinByHorizontalThen() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"I", "y"}); input.setAnswersNum(new int[] {0, 1, 1, 1, 2, 1}); Game game = new Game(input); game.choiceSide(); game.loopMove(); Subject subject = game.initWinner(); assertThat(subject.getName(), is("user")); assertThat(subject.getColor(), is(Cell.X)); } @Test public void whenManMoveFirstAndWinByVerticalThen() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"I", "y"}); input.setAnswersNum(new int[] {0, 0, 1, 0, 2, 0}); Game game = new Game(input); game.choiceSide(); game.loopMove(); Subject subject = game.initWinner(); assertThat(subject.getName(), is("user")); assertThat(subject.getColor(), is(Cell.X)); } @Test public void whenBotMoveSecondAndWinByVerticalThen() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"I", "y"}); input.setAnswersNum(new int[] {0, 1, 0, 2, 1, 1, 2, 2}); Game game = new Game(input); game.choiceSide(); game.loopMove(); Subject subject = game.initWinner(); assertThat(subject.getName(), is("bot")); assertThat(subject.getColor(), is(Cell.O)); } @Test public void whenManMoveFirstAndWinByDiagonalLeftUpToRightDownThen() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"I", "y"}); input.setAnswersNum(new int[] {0, 0, 1, 1, 2, 2}); Game game = new Game(input); game.choiceSide(); game.loopMove(); Subject subject = game.initWinner(); assertThat(subject.getName(), is("user")); assertThat(subject.getColor(), is(Cell.X)); } @Test public void whenManMoveSecondAndWinByDiagonalRightUpToLeftDownThen() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"bot", "y"}); input.setAnswersNum(new int[] {0, 2, 1, 1, 2, 0}); Game game = new Game(input); game.choiceSide(); game.loopMove(); Subject subject = game.initWinner(); assertThat(subject.getName(), is("user")); assertThat(subject.getColor(), is(Cell.O)); } @Test public void whenUseNonstandardSizeDescThenSizeItIsChoiceUser() { StubInput input = new StubInput(); input.setAnswersStr(new String[] {"bot", "n"}); input.setAnswersNum(new int[] {4, 0, 1, 1, 1, 2, 1, 3, 1}); Game game = new Game(input); game.choiceSide(); game.loopMove(); assertThat(game.getBoard().getBoard().length, is(4)); } 

At first glance, it seems to me that I need to make a definition of the size of the board, but if I initBoard() then several classes will depend on my Input (and not just the Game ), and problems with testing will begin. The same problem with getNewPosition(Subject subject) also needs input from the console. Well, such methods as initWinner() - determining the winner, loopMove() - looping the moves to a certain end of the game, or choiceSide() - choosing who goes first I do not consider taking away from this class, they clearly belong to the game. After all, the party in this is what: chose who for whom, spent the moves themselves, determined the winner.

In general, such a dilemma. Tell me how to be?

The problem is that I need only 1 class to depend on input from the console, but at the same time other methods that do not fit into the general theme of this class fall into my class.

possible example:

In the class of the game for example method:

  private Dialogs dialogs = new Dialogs(); private void initBoard() { String answer = this.dialogs.ask("Π₯ΠΎΡ‚ΠΈΡ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ стандартный Ρ€Π°Π·ΠΌΠ΅Ρ€ доски 3Ρ…3 (y/n)?"); if (answer.equals("n")) { System.out.println("Π’Π²Π΅Π΄ΠΈΡ‚Π΅ Ρ€Π°Π·ΠΌΠ΅Ρ€ доски :"); this.board = new Board(this.input.getNumber()); } else if (answer.equals("y")) { this.board = new Board(3); } else { initBoard(); } } 

And the class that encapsulates the input:

 public class Dialogs { private Input input = new ConsoleInput(); public void setInput(Input input) { this.input = input; } public String ask(String question) { System.out.println(question); return this.input.getString(); } public int askPosition(String question) { System.out.println(question); return this.input.getNumber(); } 
  • one
    Do not mix console input and your class at all. Encapsulate work with the console in a separate class, untie it. And you can separate initBoard and everything else. Because you will not need to "ask questions" in the course of initialization - Sublihim
  • >>> Do not mix input from the console and your class at all. <<< And how exactly? Can you show a little example of one method? Do you mean to bring out only questions and input? or methods entirely? - Pavel
  • The idea is that the class in your example manipulates data already received from the user. Imagine, for example, that the next step is to add a GUI, then you have to make corrections directly to your class. Ideally, your class will not need to be rewritten. - Sublihim
  • 2
    Thank. I got it. - Pavel
  • one
    @Sublihim would answer all your comments. - andreycha

0