divider

Objective

Practice composition by building a small business-domain model where an Invoice has-a Customer. Your code should safely handle a missing customer using a sentinel value.

Skills to Practice

  • Creating classes with constructors and instance variables
  • Using composition (has-a relationship)
  • Using null safely
  • Returning an AP-style sentinel value
  • Designing simple methods that describe object state
divider

Tasks

  • Create a new project named CH-Composition-Invoice
  • Create three files: Customer.java, Invoice.java, Program.java

Task 1: Customer Class

  • Add private instance variables: name and email
  • Create a constructor that initializes both values
  • Add getters: getName(), getEmail()
  • Add getContactCard() that returns something like: "Ada Lovelace <ada@company.com>"
Customer.java (Starter)
public class Customer
{
// TODO: private instance variables (name, email)
// TODO: constructor(s)
// TODO: getters (getName, getEmail)
// TODO: getContactCard() -> returns a single formatted String
}

Task 2: Invoice Class (Composition)

  • Add private instance variables: invoiceNumber, amount, paid, and customer
  • In the constructor, invoices begin UNPAID
  • The customer field may start as null
  • Add composition methods: setCustomer and clearCustomer
  • Add an AP-style sentinel method getCustomerName():
    • Return the customer's name if customer is not null
    • Return "none" if customer is null
  • Add markPaid() to set the invoice status to paid
  • Add getSummary() that returns a single-line String summary exactly like the sample output format: Invoice #____ | Customer: ____ | Amount: $____ | Status: ____
Invoice.java (Starter)
public class Invoice
{
// TODO: private instance variables
// invoiceNumber (int), amount (double), paid (boolean), customer (Customer)
// TODO: constructor
// Hint: invoices begin unpaid, and customer may be null
// TODO: getters (getInvoiceNumber, getAmount, isPaid)
// TODO: composition methods
// setCustomer(Customer customer)
// clearCustomer()
// getCustomerName() -> returns "none" if customer is null (sentinel)
// TODO: behavior methods
// markPaid()
// getSummary() -> returns a single formatted String describing the invoice
}

Task 3: Main Method

  • Create an Invoice with invoice number 1001 and amount 199.99
  • Print the invoice summary (should show Customer: none)
  • Create a Customer named Ada Lovelace with any email you choose
  • Assign the customer to the invoice and print the summary again
  • Mark the invoice paid and print the summary one last time
Program.java (Starter)
public class Program
{
public static void main(String[] args)
{
// TODO: Create:
// 1) an Invoice with no Customer yet
// 2) a Customer
// 3) assign the Customer to the Invoice
// 4) mark the Invoice paid
// 5) print invoice summaries at each stage (see Sample Output)
}
}
divider

Sample Output

Sample Output
-- Invoice Demo --
Invoice #1001 | Customer: none | Amount: $199.99 | Status: UNPAID
Assigning customer...
Invoice #1001 | Customer: Ada Lovelace | Amount: $199.99 | Status: UNPAID
Marking invoice paid...
Invoice #1001 | Customer: Ada Lovelace | Amount: $199.99 | Status: PAID

Begin Challenge