{"id":"interfaces-several","slug":"several","title":"Many classes, many interfaces","text":"### One interface, many classes\n\nStep 1's heater isn't the only switchable device in the app. Every kind of device can implement Switchable, and each one keeps the promise in its own way. A garden light counts how many times it has been switched on, since its bulb wears out:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Heater heater = new Heater(\"hall\", 21);\n        GardenLight light = new GardenLight(\"patio\");\n        heater.turnOn();\n        light.turnOn();\n        light.turnOn();\n        light.turnOff();\n        light.turnOn();\n        System.out.println(heater);\n        System.out.println(light);\n        System.out.println(heater.isOn() + \" \" + light.isOn());\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n// ==== Heater.java ====\npublic class Heater implements Switchable {\n    private String room;\n    private int degrees;\n    private boolean on;\n\n    public Heater(String room, int degrees) {\n        this.room = room;\n        this.degrees = degrees;\n        this.on = false;\n    }\n\n    @Override\n    public void turnOn() {\n        this.on = true;\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    @Override\n    public String toString() {\n        if (this.on) {\n            return \"Heater in the \" + this.room + \": on, \" + this.degrees + \" degrees\";\n        }\n        return \"Heater in the \" + this.room + \": off\";\n    }\n}\n// ==== GardenLight.java ====\npublic class GardenLight implements Switchable {\n    private String place;\n    private boolean on;\n    private int switchOns;\n\n    public GardenLight(String place) {\n        this.place = place;\n        this.on = false;\n        this.switchOns = 0;\n    }\n\n    @Override\n    public void turnOn() {\n        if (!this.on) {\n            this.on = true;\n            this.switchOns++;\n        }\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    @Override\n    public String toString() {\n        return \"Garden light (\" + this.place + \"): \" + this.switchOns + \" switch-ons\";\n    }\n}\n```\n\n```output\nHeater in the hall: on, 21 degrees\nGarden light (patio): 2 switch-ons\ntrue true\n```\n\n- Both classes have the three methods that Switchable lists, with the same headers. What the methods do is up to each class: the light's `turnOn` counts, but only when the light was off.\n- Heater and GardenLight share no code and no superclass (other than Object). The interface is all they have in common, and that's all the app's buttons need, as the next steps show.\n\n### One class, many interfaces\n\nSome devices run on a battery. What the app needs from them is another interface:\n\n```java\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n```\n\nA robot vacuum can be switched on, and it has a battery. A class can implement several interfaces: list them after `implements`, separated by commas.\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        RobotVacuum vacuum = new RobotVacuum();\n        vacuum.clean(10);\n        System.out.println(vacuum.batteryPercent());\n        vacuum.turnOn();\n        vacuum.clean(10);\n        System.out.println(vacuum.batteryPercent());\n        vacuum.turnOff();\n        vacuum.charge(45);\n        System.out.println(vacuum.batteryPercent() + \"%, on: \" + vacuum.isOn());\n    }\n}\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n// ==== RobotVacuum.java ====\npublic class RobotVacuum implements Switchable, Chargeable {\n    private boolean on;\n    private int battery;\n\n    public RobotVacuum() {\n        this.on = false;\n        this.battery = 50;\n    }\n\n    @Override\n    public void turnOn() {\n        this.on = true;\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n\n    public void clean(int minutes) {\n        if (this.on) {\n            this.battery -= 2 * minutes;\n            if (this.battery < 0) {\n                this.battery = 0;\n            }\n        }\n    }\n}\n```\n\n```output\n50\n30\n75%, on: false\n```\n\n- `implements Switchable, Chargeable` makes two promises, and RobotVacuum keeps both: it has all five methods. Leave one out, and javac says which one is missing, and from which interface.\n- `clean` is RobotVacuum's own. Neither interface knows about it.\n- The vacuum's battery isn't in either interface. The interfaces only say that there's a `batteryPercent()` to ask, and the class decides how to keep the number.\n\n### extends and implements together\n\nA class can extend only one class, but it can implement any number of interfaces, and it can do both at once. `extends` comes first. If the app had an abstract class `Appliance` for the name and the power of every device (module 34), the vacuum's header could be:\n\n```java\npublic class RobotVacuum extends Appliance implements Switchable, Chargeable {\n```\n\nThen a RobotVacuum would get Appliance's code, and still promise the methods of both interfaces. Step 9 comes back to when to use which.\n","task":"The family's electric scooter shows up in the app too. `Switchable.java` and `Chargeable.java` are ready. In `ElectricScooter.java`, write the class `ElectricScooter`, which implements both interfaces, with:\n\n- a constructor `ElectricScooter(int battery)`, which takes the battery's percentage; a new scooter is off\n- `turnOn()`, `turnOff()` and `isOn()`, as for any Switchable\n- `batteryPercent()`, which returns the battery's percentage\n- `charge(int minutes)`, which adds 2 percent for every minute, but never goes above 100\n- `ride(int km)`, which uses 5 percent for every kilometer, but only when the scooter is on, and never goes below 0\n\nPut `@Override` above each method that an interface asks for. The check runs:\n\n```java\nElectricScooter scooter = new ElectricScooter(40);\nscooter.ride(3);\nSystem.out.println(scooter.batteryPercent());\nscooter.turnOn();\nscooter.ride(3);\nSystem.out.println(scooter.isOn() + \" \" + scooter.batteryPercent());\nscooter.charge(50);\nSystem.out.println(scooter.batteryPercent());\n```\n\nand expects:\n\n```\n40\ntrue 25\n100\n```\n","kind":"code","seed":"// ==== ElectricScooter.java ====\npublic class ElectricScooter {\n\n}\n\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        ElectricScooter scooter = new ElectricScooter(40);\n        scooter.ride(3);\n        System.out.println(scooter.batteryPercent());\n        scooter.turnOn();\n        scooter.ride(3);\n        System.out.println(scooter.isOn() + \" \" + scooter.batteryPercent());\n        scooter.charge(50);\n        System.out.println(scooter.batteryPercent());\n    }\n}\n","solution":"// ==== ElectricScooter.java ====\npublic class ElectricScooter implements Switchable, Chargeable {\n    private int battery;\n    private boolean on;\n\n    public ElectricScooter(int battery) {\n        this.battery = battery;\n        this.on = false;\n    }\n\n    @Override\n    public void turnOn() {\n        this.on = true;\n    }\n\n    @Override\n    public void turnOff() {\n        this.on = false;\n    }\n\n    @Override\n    public boolean isOn() {\n        return this.on;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += 2 * minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n\n    public void ride(int km) {\n        if (this.on) {\n            this.battery -= 5 * km;\n            if (this.battery < 0) {\n                this.battery = 0;\n            }\n        }\n    }\n}\n\n// ==== Switchable.java ====\npublic interface Switchable {\n    void turnOn();\n    void turnOff();\n    boolean isOn();\n}\n\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        ElectricScooter scooter = new ElectricScooter(40);\n        scooter.ride(3);\n        System.out.println(scooter.batteryPercent());\n        scooter.turnOn();\n        scooter.ride(3);\n        System.out.println(scooter.isOn() + \" \" + scooter.batteryPercent());\n        scooter.charge(50);\n        System.out.println(scooter.batteryPercent());\n    }\n}\n","hints":["The header is `public class ElectricScooter implements Switchable, Chargeable {`. The class needs two instance variables: the battery's percentage and whether the scooter is on.","`charge` adds `2 * minutes`, and then sets the battery back to 100 if it went above. `ride` does nothing unless the scooter is on; otherwise it takes away `5 * km`, and sets the battery back to 0 if it went below. `ride` is the scooter's own, so it has no `@Override`."],"tests":[{"name":"Test 1","stdin":"","call":"ElectricScooter scooter = new ElectricScooter(40);\nscooter.ride(3);\nSystem.out.println(scooter.batteryPercent());\nscooter.turnOn();\nscooter.ride(3);\nSystem.out.println(scooter.isOn() + \" \" + scooter.batteryPercent());\nscooter.charge(50);\nSystem.out.println(scooter.batteryPercent());\n","expect":"40\ntrue 25\n100","hidden":false},{"name":"Test 2","stdin":"","call":"ElectricScooter scooter = new ElectricScooter(10);\nscooter.turnOn();\nscooter.ride(5);\nSystem.out.println(scooter.batteryPercent());\nscooter.charge(7);\nscooter.turnOff();\nscooter.ride(1);\nSystem.out.println(scooter.isOn() + \" \" + scooter.batteryPercent());\nscooter.charge(0);\nSystem.out.println(scooter.batteryPercent());\n","expect":"0\nfalse 14\n14","hidden":true},{"name":"Test 3","stdin":"","call":"Chargeable battery = new ElectricScooter(95);\nbattery.charge(1);\nSystem.out.println(battery.batteryPercent());\nSwitchable power = new ElectricScooter(0);\npower.turnOn();\nSystem.out.println(power.isOn());\n","expect":"97\ntrue","hidden":true}],"require":[{"pattern":"\\bclass\\s+ElectricScooter\\s+implements\\s+(Switchable\\s*,\\s*Chargeable|Chargeable\\s*,\\s*Switchable)\\b","message":"Write the header as `public class ElectricScooter implements Switchable, Chargeable`, so that the scooter makes both promises."},{"pattern":"@Override","min":5,"message":"Put `@Override` above each of the five methods that the two interfaces ask for."}],"forbid":[],"more":[{"task":"A laptop and a pair of headphones both implement Chargeable, but they charge at different speeds. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Laptop laptop = new Laptop(20);\n        Headphones headphones = new Headphones(10);\n        laptop.charge(30);\n        headphones.charge(12);\n        System.out.println(laptop.batteryPercent() + \" \" + headphones.batteryPercent());\n        laptop.charge(60);\n        headphones.charge(60);\n        System.out.println(laptop.batteryPercent() + \" \" + headphones.batteryPercent());\n    }\n}\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n// ==== Laptop.java ====\npublic class Laptop implements Chargeable {\n    private int battery;\n\n    public Laptop(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n// ==== Headphones.java ====\npublic class Headphones implements Chargeable {\n    private int battery;\n\n    public Headphones(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += 5 * minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Laptop laptop = new Laptop(20);\n        Headphones headphones = new Headphones(10);\n        laptop.charge(30);\n        headphones.charge(12);\n        System.out.println(laptop.batteryPercent() + \" \" + headphones.batteryPercent());\n        laptop.charge(60);\n        headphones.charge(60);\n        System.out.println(laptop.batteryPercent() + \" \" + headphones.batteryPercent());\n    }\n}\n// ==== Chargeable.java ====\npublic interface Chargeable {\n    int batteryPercent();\n    void charge(int minutes);\n}\n// ==== Laptop.java ====\npublic class Laptop implements Chargeable {\n    private int battery;\n\n    public Laptop(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n// ==== Headphones.java ====\npublic class Headphones implements Chargeable {\n    private int battery;\n\n    public Headphones(int battery) {\n        this.battery = battery;\n    }\n\n    @Override\n    public int batteryPercent() {\n        return this.battery;\n    }\n\n    @Override\n    public void charge(int minutes) {\n        this.battery += 5 * minutes;\n        if (this.battery > 100) {\n            this.battery = 100;\n        }\n    }\n}\n","hints":["Each object runs its own class's `charge`: the laptop gains 1 percent a minute, the headphones 5 percent a minute.","The laptop goes from 20 to 50, and the headphones from 10 to 70. After that, both would go past 100, so each stops at 100."],"tests":[{"name":"Output","stdin":"","expect":"50 70\n100 100","hidden":false}],"require":[],"forbid":[],"lines":["50 70","100 100"]},{"task":"The app can dim some lights. `CeilingLight` and `DeskLamp` both say `implements Dimmable`, and both have `@Override` above their methods `setBrightness` and `getBrightness`. But `Dimmable.java` is still empty, so nothing compiles. Write the interface `Dimmable`, with the two methods: `setBrightness`, which takes a percentage as an `int` and returns nothing, and `getBrightness`, which returns the percentage as an `int`. Don't change the classes. The program should print:\n\n```\n70 50\n100 0\n```\n","kind":"code","seed":"// ==== Dimmable.java ====\npublic interface Dimmable {\n\n}\n\n// ==== CeilingLight.java ====\npublic class CeilingLight implements Dimmable {\n    private int brightness;\n\n    @Override\n    public void setBrightness(int percent) {\n        if (percent < 0) {\n            this.brightness = 0;\n        } else if (percent > 100) {\n            this.brightness = 100;\n        } else {\n            this.brightness = percent;\n        }\n    }\n\n    @Override\n    public int getBrightness() {\n        return this.brightness;\n    }\n}\n\n// ==== DeskLamp.java ====\npublic class DeskLamp implements Dimmable {\n    private int brightness;\n\n    @Override\n    public void setBrightness(int percent) {\n        if (percent >= 75) {\n            this.brightness = 100;\n        } else if (percent >= 25) {\n            this.brightness = 50;\n        } else {\n            this.brightness = 0;\n        }\n    }\n\n    @Override\n    public int getBrightness() {\n        return this.brightness;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        CeilingLight ceiling = new CeilingLight();\n        DeskLamp lamp = new DeskLamp();\n        ceiling.setBrightness(70);\n        lamp.setBrightness(70);\n        System.out.println(ceiling.getBrightness() + \" \" + lamp.getBrightness());\n        ceiling.setBrightness(120);\n        lamp.setBrightness(10);\n        System.out.println(ceiling.getBrightness() + \" \" + lamp.getBrightness());\n    }\n}\n","solution":"// ==== Dimmable.java ====\npublic interface Dimmable {\n    void setBrightness(int percent);\n    int getBrightness();\n}\n\n// ==== CeilingLight.java ====\npublic class CeilingLight implements Dimmable {\n    private int brightness;\n\n    @Override\n    public void setBrightness(int percent) {\n        if (percent < 0) {\n            this.brightness = 0;\n        } else if (percent > 100) {\n            this.brightness = 100;\n        } else {\n            this.brightness = percent;\n        }\n    }\n\n    @Override\n    public int getBrightness() {\n        return this.brightness;\n    }\n}\n\n// ==== DeskLamp.java ====\npublic class DeskLamp implements Dimmable {\n    private int brightness;\n\n    @Override\n    public void setBrightness(int percent) {\n        if (percent >= 75) {\n            this.brightness = 100;\n        } else if (percent >= 25) {\n            this.brightness = 50;\n        } else {\n            this.brightness = 0;\n        }\n    }\n\n    @Override\n    public int getBrightness() {\n        return this.brightness;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        CeilingLight ceiling = new CeilingLight();\n        DeskLamp lamp = new DeskLamp();\n        ceiling.setBrightness(70);\n        lamp.setBrightness(70);\n        System.out.println(ceiling.getBrightness() + \" \" + lamp.getBrightness());\n        ceiling.setBrightness(120);\n        lamp.setBrightness(10);\n        System.out.println(ceiling.getBrightness() + \" \" + lamp.getBrightness());\n    }\n}\n","hints":["An interface lists only headers, each followed by a semicolon. Copy each header from one of the classes, leave out `public` and the body, and end it with `;`.","The interface has two lines inside its braces: `void setBrightness(int percent);` and `int getBrightness();`."],"tests":[{"name":"The program's output","stdin":"","expect":"70 50\n100 0","hidden":false},{"name":"Test 2","stdin":"","call":"Dimmable light = new DeskLamp();\nlight.setBrightness(30);\nSystem.out.println(light.getBrightness());\nlight = new CeilingLight();\nlight.setBrightness(30);\nSystem.out.println(light.getBrightness());\n","expect":"50\n30","hidden":true}],"require":[{"pattern":"\\binterface\\s+Dimmable\\b","message":"Write `Dimmable` as an interface: `public interface Dimmable`."}],"forbid":[]}]}