Skip to main content
1 of 5

Object-Oriented Calculator

I have solved an assignment (Exercise 3) from MOOC Course Object-Oriented Programming with Java, part II, but I'm not enrolled in said course.

Question: How do you refactor this code so that it follows OOP, reads better, is manageable? How can I write method names and classes better? How do you know which entities are to be made separate classes, and how to use classes efficiently?

I had thought of using a separate Command class that has a list of commands to use (whether in calculator or in any other class that uses a command style execution, like a terminal), but I didn't know how to proceed with that. Functions aren't objects in Java and generalizing seems difficult even with using Reflection in Java, especially the number and type of the return values, and typecasting new parameters with said types.

The calculator has the operations sum, difference, product and quit.

Reader Class used to simplify Scanner class (It can't be inherited, it seems)

import java.util.Scanner;


public class Reader {
    public static String readString(String prompt) {
        System.out.print(prompt);
        return new Scanner(System.in).nextLine();
    }

    public static int readInteger(String prompt) {
        return Integer.parseInt(readString(prompt));
    }
}

Calculator class

import java.util.stream.IntStream;


public class Calculator {
    private static int statistics = 0;
    private static boolean isRunning = true;

    enum Command {
        SUM,
        DIFFERENCE,
        PRODUCT,
        END
    }

    public static boolean isRunning() {
        return isRunning;
    }

    public static Command getCommand() throws IllegalCommand {
        String command = Reader.readString("command: ");
        try {
            return Command.valueOf(command.toUpperCase());
        }
        catch (Exception e) {
            throw new IllegalCommand("Command " + command + " not found");
        }
    }

    private static void printResult(String operation, int result) {
        System.out.println(operation + " of the values " + result);
    }

    private static int[] readOperands(int noOfOperands) {
        int[] array = new int[noOfOperands];
        for (int i = 0; i < noOfOperands; i++) {
            array[i] = Reader.readInteger(String.format("value%d: ", i + 1));
        }
        return array;
    }

    public static int sum(int... a) {
        return IntStream.of(a).sum();
    }

    public static int product(int... a) {
        int result = 1;
        for (int i = 0; i < a.length; i++) {
            result *= a[i];
        }
        return result;
    }

    public static void execute(Command command) {
        switch (command) {
            case SUM: {
                int[] operands = readOperands(2);
                printResult("Sum", sum(operands));
                statistics++;
                break;
            }
            case DIFFERENCE: {
                int[] operands = readOperands(2);
                printResult("Difference", operands[0] - operands[1]);
                statistics++;
                break;
            }
            case PRODUCT: {
                int[] operands = readOperands(2);
                printResult("Product", product(operands));
                statistics++;
                break;
            }
            case END: {
                System.out.println("Calculations done " + statistics);
                isRunning = false;
                break;
            }
        }
    }
}

Main

public class Main {
    public static void main(String[] args) {
        while (Calculator.isRunning()) {
            try {
                Calculator.execute(Calculator.getCommand());
                System.out.println();
            }
            catch(IllegalCommand e) {
                System.out.println(e);
            }
        }
    }
}

IllegalCommand , a custom Exception class. Is this an overkill? I just wanted to give it a type, in case it clashes with other Exception types in the future.

public class IllegalCommand extends Exception {
    public IllegalCommand(String s) {
        super(s);
    }
}