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
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.
/*
* 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)
- What does Discount.super.apply do?
- Why is a default method useful in an interface?