diff --git a/part_2/exercise_3/.gitignore b/part_2/exercise_3/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d578053fb6c37346e61ef9da56c648dac284bc98 --- /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 0000000000000000000000000000000000000000..c90834f2d607afe55e6104d8aa2cdfffb713f688 --- /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 0000000000000000000000000000000000000000..f1ec57b189cbd41fcce0db0b4658642fb10b6ebe --- /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 0000000000000000000000000000000000000000..f1d1eee8d5826c3055628a94a157eec8d56f5136 --- /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 0000000000000000000000000000000000000000..ed8ab95414a04c40e689d46ede95623aca5f6454 --- /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 0000000000000000000000000000000000000000..33a7f1973e0d6243ff31855619caa8e78d873c04 --- /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 0000000000000000000000000000000000000000..527c73c79b041af7b592f560060f4acb15052721 --- /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