Discount Policies with a Default Method

Problem

A shop has four customer types, each with a percent discount: regular 0, student 10, senior 20, member 5. The final price is price - price * percent / 100 (integer division, the fraction is dropped). A member gets one more rule: 100 is also taken off, and the final price is never below 0. Each line has TYPE PRICE; print the final price. Put the shared formula in one interface default method and let the member policy override it.

Constraints

  • 1 <= lines <= 100
  • 1 <= PRICE <= 10^6

Examples

Input

student 500
member 500

Output

450
375

Solutions

Best approachTime O(n)Space O(1)

The shared formula is written once. Most policies only give a percent. Only the member policy overrides the method, and it can still call the shared version.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Run the commands.
 * Input   : Command lines.
 * Output  : One line per answer.
 * Approach: Shared default method
 * Time    : O(n)
 * Space   : O(1)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: The interface has one abstract method (the percent) and one default method (the formula).
        interface Discount {
            int percent();

            // Step 2: Every policy gets this formula for free. A policy may override it.
            default long apply(long price) {
                return price - price * percent() / 100;
            }
        }

        static class Plain implements Discount {
            private final int percent;

            Plain(int percent) {
                this.percent = percent;
            }

            public int percent() {
                return percent;
            }
        }

        // Step 3: The member policy reuses the default formula through Discount.super and adds its own rule.
        static class Member implements Discount {
            public int percent() {
                return 5;
            }

            public long apply(long price) {
                return Math.max(0, Discount.super.apply(price) - 100);
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        java.util.Map<String, Discount> policies = new java.util.HashMap<String, Discount>();
        policies.put("regular", new Plain(0));
        policies.put("student", new Plain(10));
        policies.put("senior", new Plain(20));
        policies.put("member", new Member());
        String[] out = new String[lines.length];
        for (int i = 0; i < lines.length; i++) {
            String[] part = lines[i].split(" ");
            out[i] = String.valueOf(policies.get(part[0]).apply(Long.parseLong(part[1])));
        }
        return out;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(String.join("\n", solve(lines)));
    }
}
Hints (2)
  1. What does Discount.super.apply do?
  2. Why is a default method useful in an interface?