From e91b096de5159dae071dc3d0847b75785da33da3 Mon Sep 17 00:00:00 2001 From: Dao <comnuoc@users.noreply.gitlab.utu.fi> Date: Wed, 26 Jun 2024 00:57:26 +0300 Subject: [PATCH] feat(part2): Exercise 3. --- part_2/exercise_3/.gitignore | 30 ++++++ part_2/exercise_3/exercise_3.iml | 11 +++ part_2/exercise_3/src/CommandLineApp.java | 92 +++++++++++++++++++ part_2/exercise_3/src/Loan.java | 33 +++++++ part_2/exercise_3/src/LoanCalculator.java | 16 ++++ part_2/exercise_3/src/Main.java | 7 ++ .../exercise_3/src/SimpleLoanCalculator.java | 23 +++++ 7 files changed, 212 insertions(+) create mode 100644 part_2/exercise_3/.gitignore create mode 100644 part_2/exercise_3/exercise_3.iml create mode 100644 part_2/exercise_3/src/CommandLineApp.java create mode 100644 part_2/exercise_3/src/Loan.java create mode 100644 part_2/exercise_3/src/LoanCalculator.java create mode 100644 part_2/exercise_3/src/Main.java create mode 100644 part_2/exercise_3/src/SimpleLoanCalculator.java diff --git a/part_2/exercise_3/.gitignore b/part_2/exercise_3/.gitignore new file mode 100644 index 0000000..d578053 --- /dev/null +++ b/part_2/exercise_3/.gitignore @@ -0,0 +1,30 @@ +### IntelliJ IDEA ### +/.idea/ +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/part_2/exercise_3/exercise_3.iml b/part_2/exercise_3/exercise_3.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/part_2/exercise_3/exercise_3.iml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module> \ No newline at end of file diff --git a/part_2/exercise_3/src/CommandLineApp.java b/part_2/exercise_3/src/CommandLineApp.java new file mode 100644 index 0000000..f1ec57b --- /dev/null +++ b/part_2/exercise_3/src/CommandLineApp.java @@ -0,0 +1,92 @@ +import java.util.Scanner; + +public class CommandLineApp { + private final LoanCalculator loanCalculator; + + /* + * @.pre: loanCalculator != null + * @.post: object is constructed. + */ + public CommandLineApp(LoanCalculator loanCalculator) { + this.loanCalculator = loanCalculator; + } + + /* + * Ask for information from the user, then calculate and display monthly installment. + * + * @.pre: true + * @.post: print the monthly installment. + */ + public void run() { + while (true) { + try { + Loan loan = createLoanFromUserInput(); + double monthlyInstallment = loanCalculator.calculateMonthlyInstallment(loan); + displayMonthlyInstallment(monthlyInstallment); + + break; + } catch (LoanCalculationException e) { + System.out.println("Error: " + e.getMessage()); + } + } + } + + private Loan createLoanFromUserInput() { + Loan loan; + + Scanner reader = new Scanner(System.in); + + while (true) { + try { + double principleAmount = getInputPrincipleAmount(reader); + int loanTermInMonths = getInputLoanTerm(reader); + + loan = new Loan(principleAmount, loanTermInMonths); + + break; + } catch (ZeroOrNegativePrincipleAmountException|DisallowedLoanTermException e) { + System.out.println("Error: " + e.getMessage()); + } + } + + return loan; + } + + private void displayMonthlyInstallment(double installment) { + System.out.println("Monthly installment: " + installment); + } + + private double getInputPrincipleAmount(Scanner reader) { + double principleAmount; + + while (true) { + try { + System.out.print("Principle amount: "); + principleAmount = Double.parseDouble(reader.nextLine()); + + break; + } catch (NumberFormatException e) { + System.out.println("Error: Please enter a number"); + } + } + + return principleAmount; + } + + private int getInputLoanTerm(Scanner reader) { + int loanTermInMonths; + + while (true) { + try { + System.out.print("Loan term (in months): "); + loanTermInMonths = Integer.parseInt(reader.nextLine()); + + break; + } catch (NumberFormatException e) { + System.out.println("Error: Please enter an integer number"); + } + } + + return loanTermInMonths; + } +} diff --git a/part_2/exercise_3/src/Loan.java b/part_2/exercise_3/src/Loan.java new file mode 100644 index 0000000..f1d1eee --- /dev/null +++ b/part_2/exercise_3/src/Loan.java @@ -0,0 +1,33 @@ +/* + * @.classInvariant: + * principleAmount() > 0 && 0 <= loanTermInMonths() <= 300 + */ +public record Loan(double principleAmount, int loanTermInMonths) { + /* + * @.pre: true + * @.post: Object is constructed + * throw ZeroOrNegativePrincipleAmountException if principleAmount is less than or equal zero + * throw DisallowedLoanTermException if loanTermInMonths < 0 || loanTermInMonths > 300 + */ + public Loan { + if (principleAmount <= 0) { + throw new ZeroOrNegativePrincipleAmountException("Principle amount should be greater than zero"); + } + + if (loanTermInMonths < 0 || loanTermInMonths > 300) { + throw new DisallowedLoanTermException("Loan term in months allowed range 0-300"); + } + } +} + +class ZeroOrNegativePrincipleAmountException extends RuntimeException { + public ZeroOrNegativePrincipleAmountException(String message) { + super(message); + } +} + +class DisallowedLoanTermException extends RuntimeException { + public DisallowedLoanTermException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/part_2/exercise_3/src/LoanCalculator.java b/part_2/exercise_3/src/LoanCalculator.java new file mode 100644 index 0000000..ed8ab95 --- /dev/null +++ b/part_2/exercise_3/src/LoanCalculator.java @@ -0,0 +1,16 @@ +public interface LoanCalculator { + /* + * Calculate monthly installment based on principle amount and loan term (in months). + * + * @.pre: loan != null + * @.post: RESULT >= 0. + * throw LoanCalculationException if there is an error in calculation + */ + double calculateMonthlyInstallment(Loan loan) throws LoanCalculationException; +} + +class LoanCalculationException extends RuntimeException { + public LoanCalculationException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/part_2/exercise_3/src/Main.java b/part_2/exercise_3/src/Main.java new file mode 100644 index 0000000..33a7f19 --- /dev/null +++ b/part_2/exercise_3/src/Main.java @@ -0,0 +1,7 @@ +public class Main { + public static void main(String[] args) { + LoanCalculator calculator = new SimpleLoanCalculator(); + CommandLineApp app = new CommandLineApp(calculator); + app.run(); + } +} \ No newline at end of file diff --git a/part_2/exercise_3/src/SimpleLoanCalculator.java b/part_2/exercise_3/src/SimpleLoanCalculator.java new file mode 100644 index 0000000..527c73c --- /dev/null +++ b/part_2/exercise_3/src/SimpleLoanCalculator.java @@ -0,0 +1,23 @@ +public class SimpleLoanCalculator implements LoanCalculator { + /* + * Calculate monthly installment with simple formula + * + * @.pre: loan != null + * @.post: RESULT >= 0. + * throw ZeroLoanTermException when loan term is equal to zero. + */ + @Override + public double calculateMonthlyInstallment(Loan loan) throws LoanCalculationException { + if (0 == loan.loanTermInMonths()) { + throw new ZeroLoanTermException("Loan term should be greater than zero"); + } + + return loan.principleAmount() / loan.loanTermInMonths() + loan.principleAmount() / 240; + } +} + +class ZeroLoanTermException extends LoanCalculationException { + public ZeroLoanTermException(String message) { + super(message); + } +} \ No newline at end of file -- GitLab