backlog

Module-Java πŸ”—  

Expand all

Mandatory Tasks

These tasks will help consolidate your learning for this sprint. You should complete as many of these as possible before class on Saturday.

Sprint Challenge: Rental Summary Generator πŸ”— Clone

Sprint Challenge: Rental Summary Generator πŸ”—

Sprint Challenge: Rental Summary Generator

The code you write for this challenge is mandatory homework and should be completed and sent in a PR for review before class.

Bringing everything together: This challenge combines all the concepts you’ve learned. You’ll see how interfaces, collections, exceptions, comparisons, and streams form a cohesive system for building real applications.

Background

You are working for a company who design software for managing car leases. When a customer leases a car they pay a set rental amount each month for a given term of 1 or 3 years. Each rental is made up of capital (a portion of what the car is actually worth) and interest (what the customer pays the lease company to be allowed to lease the car, i.e. the cost of leasing the car).

The software keeps track of the above information and uses it to track payments, send invoices, generate statements and much more.

Requirements

Overview

  • Design a system that generates the monthly rentals for a given lease contract and prints a rental summary.

Rental Calculations

  • For a 1 year contract:
    • 12 rentals total
    • Monthly capital is the total cost of the vehicle / 12
    • Monthly interest is the 2% of cost of the vehicle / 12
  • For a 3 year contract:
    • 36 rentals total
    • Monthly capital is the total cost of the vehicle / 36
    • Monthly interest is the 3% of cost of the vehicle / 36
    • A rental is considered paid if it’s due date is on or before the current date

Acceptance Criteria

  • The system should log the rental summary to the console, printed in a human readable format.
  • The summary information should contain:
  • The customer’s name and age
  • The dates of the contract i.e. start and end date
  • All rentals, sorted by due date
  • The next due rental
  • The total amount of capital and interest on the contract
  • The number of remaining outstanding rentals
  • If the contract is complete, i.e. the current date is after the final rental due due, then no summary should be printed. Instead the console should print a message to say the contract is completed.
  • Passing unit tests for key classes

Developer Guidance

Let’s start with how we’ll represent the data. Create the following:

  • Class Contract, with fields
    • String customerName
    • String customerAge
    • LocalDate startDate
    • double carPrice
    • int contractLengthYears
      • And validation to check it’s either 1 or 3 years β†’ perhaps there is a better type than int that could be used here?
      • Is this the best place to add this validation? Where else could it go instead? If we do add it here would we need additional validation in our services too?
        • What are the trade-offs? Note there isn’t really a right answer here, and the best place depends on the requirements of the system:
          • e.g. There are many different types of contract, leases, loans etc and out system may support them all in some way. Do all contracts have to be 1 or 3 years, or just the type that we are creating the rental generator for?
  • Class Rental, with fields:
    • LocalDate dueDate
    • double capitalAmount
    • double interestAmount
    • boolean paid
  • Class RentalSummary, with fields containing the information required according to the acceptance criteria, including the field List<Rental> rentals.

Now think about how we’ll process the data. Create the following

  • interface RentalCalculator ,
    • With methods:
      • List<Rental> generateRentals(Contract contract);
    • And implementations
      • OneYearContractRentalGenerator
      • ThreeYearContractRentalGenerator
  • And finally how we’ll generate the rental summary data. Create the following:
  • Class RentalSummaryService with methods:
    • private Optional<RentalSummary> generateRentalSummary(Contract contract)
    • void printRentalSummary(Contract contract)
      • Calls generateRentalSummary and prints the result to the console
  • Do we need validation to check the contract length here? The answer depends on whether you’ve added it in your Contract initialization code or not!
  • It also needs to find the other information needed to fully populate the RentalSummary instance it returns

Then let’s create a main method to test what we’ve done:

public static void main(String[] args) {
 
    Contract oneYearContract = new Contract("John Smith", 25, new LocalDate(2025, 8, 12), 1, 10000);     
    Contract twoYearContract = new Contract("Michael Jones", 56, new LocalDate(2025, 12, 12), 2, 20000);
    Contract threeYearContract = new Contract("Jane Doe", 77, new LocalDate(2024, 4, 1), 3, 50000);            
    Contract completedContract = new Contract("Rosie Parker", 47, new LocalDate(2021, 7, 10), 3, 40000);             
 
    RentalSummaryService rentalSummaryService = new RentalSummaryService();
    rentalSummaryService.printRentalSummary(oneYearContract);
    rentalSummaryService.printRentalSummary(twoYearContract); // Should throw a suitable error 
    rentalSummaryService.printRentalSummary(threeYearContract);     
    rentalSummaryService.printRentalSummary(completedContract); // Should print a message to say the contract is complete      
}

Reflections

Think about the following questions, make notes and be prepared to talk through your thoughts in the workshop.

  • How did interfaces help you swap out implementations (e.g. different RentalCalculators)?
  • Why did you choose specific collection types (List vs Set vs Map)?
  • Where did exceptions help you handle errors gracefully?
  • How did you decide where to implement the validation for the contract length? What are the trade-offs you considered? In particular think about callers of your methods; can you guarantee anything about the parameters passed down from other places in the system?
  • How did streams make your data processing more readable than loops?
  • How did Optionals help you avoid NullPointerException?
  • Do you think the classes and interfaces we’ve used here provide the best way of modelling this information? Can you think of any improvements? Think about readability / complexity / maintenance etc
  • When developing production-ready software, multiple developers often work on the same code. If someone else came across your code and needed to make a change (e.g. to add support for 2-year contracts), do you think they would find it easy? I.e. is your code readable, well-documented, open for extension etc?
  • If you didn’t have access to Collections, streams or interfaces would this development have been easier or harder? Where would the challenges lie?

Submission & Review

Fork the coursework repo to your own GitHub account. Make regular small commits with clear messages. When you are ready, open a Pull Request to the CYF repo. Make sure you fill in the PR template provided. A volunteer will review your submission and send you feedback.