Building a Simple Java Calculator using Clean Architecture means splitting your code into distinct concentric layers to separate core business math from presentation details and frameworks.
The primary rule of Clean Architecture is the Dependency Rule: code dependencies must only point inwards, meaning your core math calculations know absolutely nothing about user interfaces, consoles, or database tools.
┌─────────────────────────────────────────┐ │ Layer 3: Frameworks & Drivers (Console) │ └────────────────────┬────────────────────┘ ▼ ┌─────────────────────────────────────────┐ │ Layer 2: Interface Adapters (Presenter) │ └────────────────────┬────────────────────┘ ▼ ┌─────────────────────────────────────────┐ │ Layer 1: Core Use Cases (Math Logic) │ └─────────────────────────────────────────┘ 1. Core Layer (Use Cases & Entities)
This layer contains the absolute business rules. It uses pure Java and has zero external imports. First, we define an interface for our core operations:
package domain.usecase; public interface CalculatorUseCase { double execute(double num1, double num2, String operator); } Use code with caution.
Next, we implement the application math logic. Notice that it does not print text or read keyboard inputs:
package domain.usecase; public class CalculatorInteractor implements CalculatorUseCase { @Override public double execute(double num1, double num2, String operator) { return switch (operator) { case “+” -> num1 + num2; case “-” -> num1 - num2; case “*” -> num1num2; case “/” -> { if (num2 == 0) { throw new ArithmeticException(“Division by zero error.”); } yield num1 / num2; } default -> throw new IllegalArgumentException(“Unknown operator: ” + operator); }; } } Use code with caution. 2. Interface Adapter Layer (Presenters & Controllers)
This layer translates data between the core format and the format required by the presentation layer.
package adapter.presenter; import domain.usecase.CalculatorUseCase; public class CalculatorPresenter { private final CalculatorUseCase useCase; public CalculatorPresenter(CalculatorUseCase useCase) { this.useCase = useCase; } public String handleCalculation(String input1, String input2, String operator) { try { double num1 = Double.parseDouble(input1); double num2 = Double.parseDouble(input2); double result = useCase.execute(num1, num2, operator); return “Result: ” + result; } catch (NumberFormatException e) { return “Error: Invalid numeric input input.”; } catch (Exception e) { return “Error: ” + e.getMessage(); } } } Use code with caution. 3. Frameworks & Drivers Layer (UI/Console Interface)
This outermost layer consists of configurations, UI screens, tools, and entry points. We implement a basic command-line console layout here, though you could swap this for a web GUI without modifying your math classes.
package main; import adapter.presenter.CalculatorPresenter; import domain.usecase.CalculatorInteractor; import domain.usecase.CalculatorUseCase; import java.util.Scanner; public class MainApp { public static void main(String[] args) { // Wire dependencies up (Inversion of Control manually) CalculatorUseCase useCase = new CalculatorInteractor(); CalculatorPresenter presenter = new CalculatorPresenter(useCase); Scanner scanner = new Scanner(System.in); System.out.println(“=== Clean Architecture Calculator ===”); System.out.print(“Enter first number: “); String num1 = scanner.nextLine(); System.out.print(“Enter operator (+, -, *, /): “); String op = scanner.nextLine(); System.out.print(“Enter second number: “); String num2 = scanner.nextLine(); // Pass control to the adapter layer String output = presenter.handleCalculation(num1, num2, op); System.out.println(output); scanner.close(); } } Use code with caution. Key Advantages of This Layout
Isolated Testing: You can write unit tests for CalculatorInteractor without spinning up interfaces or dealing with system mock tools.
UI Agnostic: Changing your calculator interface to a desktop GUI app like Java Swing or a web service requires rewriting only the MainApp view layer. The business core remains intact.
Separation of Concerns: Input validation bugs (NumberFormatException) are strictly contained inside the adapter layer and never corrupt the core business process logic. If you would like to expand this project layout,
Integrating a Dependency Injection framework like Spring or Guice.
Implementing complex math operations like exponents and memory functions. raulh82vlc/SimpleCalculator: Simple calculator … – GitHub