Приветствую всех, кто читает этот пост! Благодаря своей работе я часто сталкиваюсь с начинающими программистами и смотрю на их код. Иногда это красиво, иногда нет, но я понимаю, что человек учится, и чем дальше он осваивает лучшие практики и технологии, тем лучше становится его код. Но я все же хотел бы уделить некоторое внимание такой простой задаче, с которой сталкиваются практически все начинающие программисты, – написанию калькулятора
Вот что пишут начинающие программисты:
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
int sum = 0;
int number1 = 0, number2 = 0;
boolean correct = true;
char operation1;
Scanner sc = new Scanner(System.in);
System.out.println("Enter first number:");
while (!sc.hasNextInt()) {
System.out.println("Sorry, it is not a digit. Try again, please");
sc.next();
}
number1 = sc.nextInt();
System.out.println("Thanks! You entered number: " + number1);
System.out.println("Enter a number:");
while (!sc.hasNextInt()) {
System.out.println("It is not a digit. Try again");
sc.next();
}
number2 = sc.nextInt();
System.out.println("Thanks! It is a digit " + number2);
do {
correct = true;
System.out.println("What would you like to do? + - / *");
operation1 = sc.next().charAt(0);
switch (operation1) {
case '+':
sum = number1 + number2;
System.out.println("Sum of this two equals to " + sum);
break;
case '-':
sum = number1 - number2;
System.out.println("The difference between equals to: " + sum);
break;
case '/':
if (number2 != 0) {
sum = number1 / number2;
System.out.println("Divied equals to: " + sum);
} else {
System.out.println("Divided by zero is not allowed.");
correct = false;
}
break;
case '*':
sum = number1 * number2;
System.out.println("Multiplication of this two: " + sum);
break;
default:
System.out.println("Unknow operation");
correct = false;
break;
}
} while (correct != true);
}
}
Какие проблемы вы видите в этом коде? Я вижу следующие проблемы
- Все написано в основном методе и, безусловно, представляет собой более 10 строк
- Для этого кода нет тестов, то есть нет уверенности в том, что он будет работать правильно
- Структурный стиль программирования – оператор switch поощряет это
- С помощью сканера, но это можно простить, потому что у него есть удобные методы для получения номеров сразу.
Как бы вы исправили этот код? Я бы исправил данный код следующим образом
- Создал бы интерфейс операций для всех операций с числами
public interface Operation {
int execute(int a, int b);
}
И соответственно я бы реализовал этот интерфейс в следующих классах
public class Addition implements Operation {
@Override
public int execute(int a, int b) {
return a + b;
}
}
public class Deduction implements Operation {
@Override
public int execute(int a, int b) {
return a - b;
}
}
public class Division implements Operation {
@Override
public int execute(int a, int b) {
return a / b;
}
}
public class Multiplication implements Operation {
@Override
public int execute(int a, int b) {
return a * b;
}
}
Я бы сделал то же самое с методами ввода и вывода, но прежде чем мы начнем их писать, давайте добавим очень полезную библиотеку – Apache Commons
org.apache.commons commons-lang3 3.11
Интерфейс для работы с вводом-выводом информации будет выглядеть следующим образом
public interface IO {
int getNumber(String message, String errorMessage);
Operation getOperation(String message);
void printResult(String result);
}
И вот как будет выглядеть его реализация
public class ConsoleIO implements IO {
private final BufferedReader bufferedReader;
private final List allowedOperation;
private Map operationMap;
public ConsoleIO(final List allowedOperation) {
this.bufferedReader = new BufferedReader(new InputStreamReader(System.in));
this.allowedOperation = allowedOperation;
fullFillServiceMap();
}
@Override
public int getNumber(String message, String errorMessage) {
if (StringUtils.isNotBlank(message)) {
System.out.println(message);
}
boolean validNumber = false;
int numberResult = 0;
while (!validNumber) {
try {
String line = bufferedReader.readLine();
if (StringUtils.isNumeric(line)) {
numberResult = Integer.parseInt(line);
validNumber = true;
}
} catch (IOException e) {
System.out.println(errorMessage);
throw new RuntimeException(e);
}
}
return numberResult;
}
@Override
public Operation getOperation(String operationKey) {
if (this.allowedOperation == null || this.allowedOperation.isEmpty()) {
throw new IllegalStateException("Не заданы разрешенные операции");
}
boolean validOperation = false;
while (!validOperation) {
if (this.allowedOperation.contains(operationKey)) {
validOperation = true;
}
}
return operationMap.get(operationKey);
}
@Override
public void printResult(String result) {
System.out.println(result);
}
private void fullFillServiceMap() {
this.operationMap = new HashMap<>();
this.operationMap.put("+", new Addition());
this.operationMap.put("-", new Deduction());
this.operationMap.put("*", new Multiplication());
this.operationMap.put("/", new Division());
}
}
Единственное, что осталось, – это написать сам калькулятор, то есть обработчик операций
public class Calculator {
private IO io;
private Map idOperationKeys;
public Calculator(IO io) {
this.io = io;
fillMap();
}
public void launch() {
boolean working = true;
while (working) {
int number = io.getNumber("1.Addition\n2.Substraction\n3.Multiplication\n4.Divison\n5.Exit", "Not valid number");
if (number == 5) {
working = false;
} else {
int result = 0;
try {
result = io.getOperation(idOperationKeys.get(number))
.execute(
io.getNumber("Enter first number", "Not valid number"),
io.getNumber("Enter second number", "Not valid number")
);
io.printResult("The result of you operation equals to " + result);
} catch (RuntimeException runtimeException) {
io.printResult(runtimeException.getMessage());
}
}
}
}
private void fillMap() {
idOperationKeys = new HashMap<>();
idOperationKeys.put(1, "+");
idOperationKeys.put(2, "-");
idOperationKeys.put(3, "*");
idOperationKeys.put(4, "/");
}
}
Что ж, для того чтобы наша программа наконец заработала, мы отредактируем основной метод
public class App {
public static void main(String[] args) {
new Calculator(
new ConsoleIO(
Arrays.asList("+", "-", "*", "/")
)
).launch();
}
}
Моя реализация не претендует на звание лучшего решения, однако я вижу в ней несколько преимуществ:
- Этот код проще для написания тестов
- Код открыт для добавления новых функций
- Никаких зависимостей от какой-либо реализации – мы используем абстракцию для ввода и вывода информации
Это все для меня, спасибо за ваше внимание!
Если вам понравилась статья, поделитесь с друзьями и поставьте лайк
Подписывайтесь и оставляйте свои комментарии
Оригинал: “https://dev.to/vrnsky/stop-writing-code-in-main-method-2bff”