Вопрос по ООП Java. Нужен совет

93
04 января 2022, 04:40

Интересно мнение экспертов. Программа угадывает задуманное число, и пишет за скольо ходов она угадала.

Класс Main

public class Main {
    public static void main(String[] args) {
        GuessingConsoleGame game = new GuessingConsoleGame();
        game.Start();
    }
}

Класс GuessingConsoleGame

import java.util.Scanner;
public class GuessingConsoleGame {
    public void Start() {
        Scanner scanner = new Scanner(System.in);
        GuessingBinary guessing = new GuessingBinary();
        System.out.println("Guessing game number");
        System.out.println("If we guessed your num - press [y]" +
                "\nIf your number bigger than proposed by us - press [>]" +
                "\nIf your number less than proposed us - press [<]");
        System.out.print("Enter min border: ");
        int min = scanner.nextInt();
        System.out.print("Enter max border: ");
        int max = scanner.nextInt();
        while (max < min) {
            System.out.println("Max can't be less than min. Try again");
            System.out.print("Enter max border: ");
            max = scanner.nextInt();
        }
        guessing.initialization(min, max);
        while (!guessing.isTrue()) {
            System.out.println("Attempt: " + guessing.getCount());
            System.out.println("Your num is: " + guessing.getGuessedNum());
            System.out.print(":");
            guessing.guessing(scanner.next());
        }
    }
}

Класс GuessingBinary

public class GuessingBinary {
private int min, max;
    private int count;
    private int guessedNum;
    private boolean isTrue;
    private int half;
    public void initialization(int min, int max) {
        this.min = min;
        this.max = max;
        isTrue = false;
        count = 1;
        half = max / 2;
        guessedNum = half;
    }
    public int getGuessedNum() {
        return guessedNum;
    }
    public int getCount() {
        return count;
    }
    public boolean isTrue() {
        return isTrue;
    }
    public void guessing(String string) {
        if (string.equals("y")) {
            isTrue = true;
        } else if (string.equals("<")) {
            max = half;
        } else if (string.equals(">")) {
            min = half;
        }
        half = ((max - min) / 2) + min;
        count++;
        guessedNum = half;
    }
}
Answer 1

Затолкать все методы в один класс != хорошо.

По сути, у вас тут плохо всё.

1) у вас есть класс Guessing, но пучему то он делает не только Guessing, но ещё и занимаетеся валидацией, выводом в консоль, хренением состояния. Это всё нарушает S из SOLID и делает вашу программу более связной. Точнее, выводит её на максимальный уровень связности, так как у вас по сути все делает один класс. Вы говорите, что применяете ООП - поясните, какие приемы, кроме создания класса, из ООП вы применили?

2) Единственно полезный метод из всего класса Guessing у вас - это метод guessedNum, который внезапно приватный. То есть у вас класс предназначен для угадывания числа, но метод угадать число у него недоступен. Это как так?

3) Вот в этом методе

public void setMax(int max) {
    if (min > max) {
        System.out.println("Max value can't be less than min. So we have changed them");
        this.max = min;
        min = max;
    } else {
        this.max = max;
    }
}

Вы решаете за юзера, какое вам надо угадать число. В чем смысл угадывания числа, которое вы сами за юзера и назначили? Почему указанием значений по умолчанию занимается класс, который эти значения угадывает? Вы не видите тут логических противоречий?

Что можно было бы сделать:

чтобы понять ООП немножко получше, я добавлю вам условие - что если у нас будет несколько способов угадать число? Тогда нам понадобится интерфейс, например

interface GuessingNumber {
    int guessedNum(int min, int max, int userNum);
}

Напишекм парочку имплементаций, ваша

class GuessingBinary implements GuessingNumber {
    @Override
    public int guessedNum(int min, int max, int userNum) {
        int count = 0;
        boolean isTrue = false;
        int half = max / 2;
        while (!isTrue) {
            count++;
            if (userNum == half || userNum == max || userNum == min) {
                isTrue = true;
            } else if (userNum < half) {
                max = half;
            } else {
                min = half;
            }
            half = ((max - min) / 2) + min;
        }
        return count;
    }
}

Линейная

class GuessingLinear implements GuessingNumber {
    @Override
    public int guessedNum(int min, int max, int userNum) {
        int count = 0;
        for (int i = min; i <= max; i++) {
            count++;
            if (i == userNum) break;
        }
        return count;
    }
}

Напишем класс для вашей игры

class GuessingConsoleGame {
    private GuessingNumber guessing;
    public GuessingConsoleGame(GuessingNumber guessing) {
        this.guessing = guessing;
    }
    public void Start() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter min border: ");
        int min = scanner.nextInt();
        System.out.println("Enter max border: ");
        int max = scanner.nextInt();
        while (max < min) {
            System.out.println("max cant be less than " + min + ". Please, try again.");
            System.out.println("Enter max border: ");
            max = scanner.nextInt();
        }
        System.out.print("Enter num: ");
        int userNum = scanner.nextInt();
        while (userNum < min || userNum > max) {
            System.out.println("num should be between " + min + " and " + max + ". Please, try again.");
            System.out.println("Enter num: ");
            userNum = scanner.nextInt();
        }
        int guessCount = guessing.guessedNum(min, max, userNum);
        System.out.println("You guessed: " + userNum + "\nWe guessed num on " + guessCount + " try");
    }
}

Теперь мы можем содавать класс игры и подсовывать ему любую имплементацию для угадываний, например

public static void main(String[] args) {
    GuessingNumber guessing = new GuessingBinary();
    GuessingConsoleGame game = new GuessingConsoleGame(guessing);
    game.Start();
}

Что улучшилось: мы отвязали логику угадывания числа от консоли и вообще от всего. Захотите писать мобильное приложение с угадыванием или сайт - сможете переиспользовать созданные классы. Захотите добавить ещё один способ угадывания числа - достаточно написать 1 класс. реализовать интерфейс, и подставить этот класс в конструктор игры.

Что можно улучшить: класс игры все ещё зависит от консоли. Если вывести ввод/вывод в отдельные классы, то получите ещё большую гибкоть. Но делать это стоит только если вы в самом деле планируете иметь несколько способов ввода, так как просто беспричинное добавление классов увеличивает сложность и не приносит профита.

Что почитать: раз, два, три, ну и про SOLID почитайте и паттерны, лишним не будет.

READ ALSO
Как превратить строку в формулу?

Как превратить строку в формулу?

Допустим, я прошу пользователя ввести любую формулу графика, для простоты пусть это будет

240
Как сделать такие разрывы в border?

Как сделать такие разрывы в border?

С помощью псевдоэлэментов, градиента или же другие методы?

198
Редактировать .SVG для анимации - XML

Редактировать .SVG для анимации - XML

Как правильно повернуть диск этого image?

196
Django 2 Настройка системы комментариев

Django 2 Настройка системы комментариев

Проблема следующая: когда я добавляю новый комментарий под публикацией на своем сайте, он отображается нормально, но если вдруг зажать какую-либо...

86