Java Arena
Step 4 of 9

An interface as a parameter's type

A watch shop sells products, such as straps and alarm clocks, and it does repairs, which cost 2 dollars a minute. A product and a repair have little in common: a product has a name and a fixed price, and a repair has minutes of work. But at the checkout, both need a line on the receipt and a price. That's an interface:

public interface Priced {
    String label();
    int price();
}

A method whose parameter has the type Priced accepts both:

Main.java
public class Main {
    public static void main(String[] args) {
        Product strap = new Product("Watch strap", 12);
        Repair repair = new Repair(25);
        printLine(strap);
        printLine(repair);
        printLine(new Product("Alarm clock", 45));
    }

    public static void printLine(Priced item) {
        System.out.println(item.label() + ": " + item.price() + " dollars");
    }
}
Priced.java
public interface Priced {
    String label();
    int price();
}
Product.java
public class Product implements Priced {
    private String name;
    private int dollars;

    public Product(String name, int dollars) {
        this.name = name;
        this.dollars = dollars;
    }

    @Override
    public String label() {
        return this.name;
    }

    @Override
    public int price() {
        return this.dollars;
    }
}
Repair.java
public class Repair implements Priced {
    private int minutes;

    public Repair(int minutes) {
        this.minutes = minutes;
    }

    @Override
    public String label() {
        return "Repair, " + this.minutes + " minutes";
    }

    @Override
    public int price() {
        return 2 * this.minutes;
    }
}
Output
Watch strap: 12 dollars
Repair, 25 minutes: 50 dollars
Alarm clock: 45 dollars
  • printLine's parameter has the type Priced, so the method accepts an object of any class that implements Priced. The call printLine(strap) works as if it said Priced item = strap;, which compiles because a Product is a Priced.
  • Inside the method, item is a Priced variable, like step 3's device. The method may call label() and price(), and each object runs its own: the product gives its fixed price, the repair works its price out from the minutes.

One method for every kind of item

Without the interface, printLine would need two versions, printLine(Product item) and printLine(Repair item), with the same code in each (overloading, module 21). Every new thing the shop sells would need one more.

With the interface, printLine is written once, and it depends only on what it uses: a label and a price. When the shop starts engraving watches, a new class Engraving that implements Priced works with printLine at once, without any change to it. The last challenge of this step shows that.

Java's own classes work this way too. System.out.println can print any object because it has a version whose parameter's type is Object, and step 6 shows that Collections.sort takes an interface.

Your task

Challenge 1 of 3

In Checkout.java, write the class Checkout for the watch shop's till. Priced.java, Product.java and Repair.java are ready. A checkout has:

  • a constructor without parameters; a new checkout has a total of 0 and no items
  • scan(Priced item), which prints the item's line, such as Watch strap: 12 dollars, adds its price to the total, and counts it
  • total(), which returns the total in dollars
  • itemCount(), which returns how many items have been scanned

The check runs:

Checkout checkout = new Checkout();
checkout.scan(new Product("Watch strap", 12));
checkout.scan(new Repair(25));
System.out.println("Total: " + checkout.total() + " dollars for " + checkout.itemCount() + " items");

and expects:

Watch strap: 12 dollars
Repair, 25 minutes: 50 dollars
Total: 62 dollars for 2 items

Challenge 2

The method cheaper takes two priced things, and returns the label of the cheaper one. What does this program print?

Challenge 3

The shop starts engraving watches: 3 dollars a letter, but never more than 30 dollars for one engraving. In Engraving.java, write the class Engraving, which implements Priced, with:

  • a constructor Engraving(String text), where the text is one word, such as a name, so its length() is its number of letters
  • label(), which returns Engraving, Anna, with the engraving's own text
  • price(), which returns the price in dollars

Main.java has this step's printLine, and it doesn't change: it takes engravings as soon as Engraving implements Priced. The check runs:

printLine(new Engraving("Anna"));
printLine(new Engraving("Christopher"));
printLine(new Product("Alarm clock", 45));

and expects:

Engraving, Anna: 12 dollars
Engraving, Christopher: 30 dollars
Alarm clock: 45 dollars