{"id":"text-ui-ui-class","slug":"user-interface-class","title":"A class for the user interface","text":"The logic of the practice log is now in `PracticeLog`, but `main` still holds the whole user interface: the loop, the reading and the printing. The next move gives the user interface a class of its own too, called `UserInterface`. Its constructor takes the two things it works with, a Scanner and the logic object, and its method `start()` runs the command loop. What's left of `main` only puts the program together:\n\n```java\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        PracticeLog log = new PracticeLog();\n        UserInterface ui = new UserInterface(scanner, log);\n        ui.start();\n    }\n}\n// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    private Scanner scanner;\n    private PracticeLog log;\n\n    public UserInterface(Scanner scanner, PracticeLog log) {\n        this.scanner = scanner;\n        this.log = log;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Keep practicing!\");\n                break;\n            }\n            if (command.equals(\"log\")) {\n                int minutes = Integer.valueOf(this.scanner.nextLine());\n                this.log.add(minutes);\n                System.out.println(\"Logged \" + minutes + \" minutes\");\n            } else if (command.equals(\"total\")) {\n                System.out.println(\"Total: \" + this.log.total() + \" minutes\");\n            } else if (command.equals(\"longest\")) {\n                System.out.println(\"Longest: \" + this.log.longest() + \" minutes\");\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n// ==== PracticeLog.java ====\nimport java.util.ArrayList;\n\npublic class PracticeLog {\n    private ArrayList<Integer> sessions;\n\n    public PracticeLog() {\n        this.sessions = new ArrayList<>();\n    }\n\n    public void add(int minutes) {\n        this.sessions.add(minutes);\n    }\n\n    public int total() {\n        int total = 0;\n        for (int minutes : this.sessions) {\n            total = total + minutes;\n        }\n        return total;\n    }\n\n    public int longest() {\n        int longest = 0;\n        for (int minutes : this.sessions) {\n            if (minutes > longest) {\n                longest = minutes;\n            }\n        }\n        return longest;\n    }\n}\n```\n\n```input\nlog\n25\nlog\n40\ntotal\nlog\n15\nlongest\nquit\n```\n\n```output\n> Logged 25 minutes\n> Logged 40 minutes\n> Total: 65 minutes\n> Logged 15 minutes\n> Longest: 40 minutes\n> Keep practicing!\n```\n\n- `UserInterface` keeps the Scanner and the log in instance variables. The constructor gets them as parameters, and from then on every method of the class can use them as `this.scanner` and `this.log`.\n- `start()` holds the loop that used to be in `main`. It returns when the user quits, and then `main` ends too.\n- `main` creates the objects, gives the user interface what it needs, and starts it. It's four lines long, and it stays that short however many commands the program gets.\n- `PracticeLog` didn't change at all. It never knew who was calling it.\n\n### Why the Scanner is a parameter\n\nThe user interface could create a Scanner of its own. It's given one instead, for two reasons:\n\n- A program should have only one Scanner reading `System.in`. A Scanner reads the input in chunks: to give you one line, it may take in more of what's waiting, and keep the rest for its next calls. A second Scanner on `System.in` would never see what the first one took in, so it could miss lines.\n- The user interface then works with any Scanner. As module 20 showed, a Scanner can read a String, so the whole program can run from commands written in the code, without anyone typing:\n\n```java\nPracticeLog log = new PracticeLog();\nUserInterface ui = new UserInterface(new Scanner(\"log\\n30\\nlog\\n45\\nquit\\n\"), log);\nui.start();\nSystem.out.println(log.total());\n```\n\nThis runs `log` twice and then `quit`, so it prints the three answers, and then `75`. The log was created outside the user interface and handed to it, so `log` here and `this.log` in the user interface refer to the same PracticeLog object. That's why the code that created it can still ask it for the total after `start()` has returned. Some of the hidden checks in this module run your user interface in this way.\n","task":"A rain barrel in a garden collects rain, and water can be taken from it to water the plants. The logic is ready in `RainBarrel.java`: `rain(int liters)` adds water, but never more than fits, `take(int liters)` returns `false` and changes nothing if there isn't that much water, and `getLiters()` returns how much water there is. `Main.java` is ready too. Write `UserInterface.java`: its constructor takes a `Scanner` and a `RainBarrel`, and `start()` reads commands, with the prompt `> ` before each one:\n\n- `rain`: the next line is a number of liters. Add them to the barrel and print `Barrel: ` and the liters in it, like `Barrel: 40 liters`.\n- `water`: the next line is a number of liters. Take them from the barrel and print `Barrel: ` and the liters left, or `Not enough water`.\n- `level`: print `Barrel: ` and the liters.\n- `quit`: print `Bye!` and return.\n- Anything else: print `Unknown command: ` and the command.\n\nFor the input shown, the program prints:\n\n```\n> Barrel: 40 liters\n> Barrel: 25 liters\n> Not enough water\n> Barrel: 100 liters\n> Barrel: 100 liters\n> Bye!\n```\n","kind":"code","seed":"// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    // Write the instance variables, the constructor and start() here.\n}\n\n// ==== RainBarrel.java ====\npublic class RainBarrel {\n    private int capacity;\n    private int liters;\n\n    public RainBarrel(int capacity) {\n        this.capacity = capacity;\n        this.liters = 0;\n    }\n\n    public void rain(int liters) {\n        this.liters = this.liters + liters;\n        if (this.liters > this.capacity) {\n            this.liters = this.capacity;\n        }\n    }\n\n    public boolean take(int liters) {\n        if (liters > this.liters) {\n            return false;\n        }\n        this.liters = this.liters - liters;\n        return true;\n    }\n\n    public int getLiters() {\n        return this.liters;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        RainBarrel barrel = new RainBarrel(100);\n        UserInterface ui = new UserInterface(scanner, barrel);\n        ui.start();\n    }\n}\n","solution":"// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    // Write the instance variables, the constructor and start() here.\n    private Scanner scanner;\n    private RainBarrel barrel;\n\n    public UserInterface(Scanner scanner, RainBarrel barrel) {\n        this.scanner = scanner;\n        this.barrel = barrel;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Bye!\");\n                break;\n            }\n            if (command.equals(\"rain\")) {\n                int liters = Integer.valueOf(this.scanner.nextLine());\n                this.barrel.rain(liters);\n                System.out.println(\"Barrel: \" + this.barrel.getLiters() + \" liters\");\n            } else if (command.equals(\"water\")) {\n                int liters = Integer.valueOf(this.scanner.nextLine());\n                if (this.barrel.take(liters)) {\n                    System.out.println(\"Barrel: \" + this.barrel.getLiters() + \" liters\");\n                } else {\n                    System.out.println(\"Not enough water\");\n                }\n            } else if (command.equals(\"level\")) {\n                System.out.println(\"Barrel: \" + this.barrel.getLiters() + \" liters\");\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n\n// ==== RainBarrel.java ====\npublic class RainBarrel {\n    private int capacity;\n    private int liters;\n\n    public RainBarrel(int capacity) {\n        this.capacity = capacity;\n        this.liters = 0;\n    }\n\n    public void rain(int liters) {\n        this.liters = this.liters + liters;\n        if (this.liters > this.capacity) {\n            this.liters = this.capacity;\n        }\n    }\n\n    public boolean take(int liters) {\n        if (liters > this.liters) {\n            return false;\n        }\n        this.liters = this.liters - liters;\n        return true;\n    }\n\n    public int getLiters() {\n        return this.liters;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        RainBarrel barrel = new RainBarrel(100);\n        UserInterface ui = new UserInterface(scanner, barrel);\n        ui.start();\n    }\n}\n","hints":["Two instance variables, `private Scanner scanner;` and `private RainBarrel barrel;`, set in the constructor `public UserInterface(Scanner scanner, RainBarrel barrel)`.","`start()` is a `public void` method with the command loop in it, like the practice log's. Read with `this.scanner.nextLine()`, and read the liters with `Integer.valueOf(this.scanner.nextLine())`."],"tests":[{"name":"Test 1","stdin":"rain\n40\nwater\n15\nwater\n30\nrain\n90\nlevel\nquit\n","expect":"> Barrel: 40 liters\n> Barrel: 25 liters\n> Not enough water\n> Barrel: 100 liters\n> Barrel: 100 liters\n> Bye!","hidden":false},{"name":"Test 2","stdin":"level\nwater\n1\nfill\nrain\n5\nwater\n5\nquit\n","expect":"> Barrel: 0 liters\n> Not enough water\n> Unknown command: fill\n> Barrel: 5 liters\n> Barrel: 0 liters\n> Bye!","hidden":true},{"name":"Test 3","stdin":"","call":"RainBarrel small = new RainBarrel(50);\nUserInterface ui = new UserInterface(new Scanner(\"rain\\n80\\nwater\\n50\\nlevel\\nquit\\n\"), small);\nui.start();\nSystem.out.println(small.getLiters());\n","expect":"> Barrel: 50 liters\n> Barrel: 0 liters\n> Barrel: 0 liters\n> Bye!\n0","hidden":true}],"require":[],"forbid":[{"pattern":"new\\s+Scanner\\b[\\s\\S]*\\bclass\\s+RainBarrel\\b","message":"Use the Scanner the constructor gets: `main` already made one, and one Scanner is enough."}],"more":[{"task":"Here's the thermostat of the previous step, with its user interface in `main`. Move the user interface into `UserInterface.java`: a constructor that takes a `Scanner` and a `Thermostat`, and a method `start()` with the command loop. Then `main` only creates the Scanner, the thermostat with the target 21, and the user interface, and calls `start()`. The program prints exactly what it did. For the input shown:\n\n```\n> Target: 21 degrees\n> Target: 22 degrees\n> Target: 23 degrees\n> Target: 22 degrees\n> Unknown command: heat\n> Thermostat off\n```\n","kind":"code","seed":"// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    // Move the user interface here.\n}\n\n// ==== Thermostat.java ====\npublic class Thermostat {\n    private int target;\n\n    public Thermostat(int target) {\n        this.target = target;\n    }\n\n    public boolean warmer() {\n        if (this.target >= 28) {\n            return false;\n        }\n        this.target++;\n        return true;\n    }\n\n    public boolean cooler() {\n        if (this.target <= 15) {\n            return false;\n        }\n        this.target--;\n        return true;\n    }\n\n    public int getTarget() {\n        return this.target;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        Thermostat thermostat = new Thermostat(21);\n        while (true) {\n            System.out.print(\"> \");\n            String command = scanner.nextLine();\n            if (command.equals(\"off\")) {\n                System.out.println(\"Thermostat off\");\n                break;\n            }\n            if (command.equals(\"up\")) {\n                if (thermostat.warmer()) {\n                    System.out.println(\"Target: \" + thermostat.getTarget() + \" degrees\");\n                } else {\n                    System.out.println(\"Already at the maximum\");\n                }\n            } else if (command.equals(\"down\")) {\n                if (thermostat.cooler()) {\n                    System.out.println(\"Target: \" + thermostat.getTarget() + \" degrees\");\n                } else {\n                    System.out.println(\"Already at the minimum\");\n                }\n            } else if (command.equals(\"show\")) {\n                System.out.println(\"Target: \" + thermostat.getTarget() + \" degrees\");\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n","solution":"// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    // Move the user interface here.\n    private Scanner scanner;\n    private Thermostat thermostat;\n\n    public UserInterface(Scanner scanner, Thermostat thermostat) {\n        this.scanner = scanner;\n        this.thermostat = thermostat;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"off\")) {\n                System.out.println(\"Thermostat off\");\n                break;\n            }\n            if (command.equals(\"up\")) {\n                if (this.thermostat.warmer()) {\n                    System.out.println(\"Target: \" + this.thermostat.getTarget() + \" degrees\");\n                } else {\n                    System.out.println(\"Already at the maximum\");\n                }\n            } else if (command.equals(\"down\")) {\n                if (this.thermostat.cooler()) {\n                    System.out.println(\"Target: \" + this.thermostat.getTarget() + \" degrees\");\n                } else {\n                    System.out.println(\"Already at the minimum\");\n                }\n            } else if (command.equals(\"show\")) {\n                System.out.println(\"Target: \" + this.thermostat.getTarget() + \" degrees\");\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n\n// ==== Thermostat.java ====\npublic class Thermostat {\n    private int target;\n\n    public Thermostat(int target) {\n        this.target = target;\n    }\n\n    public boolean warmer() {\n        if (this.target >= 28) {\n            return false;\n        }\n        this.target++;\n        return true;\n    }\n\n    public boolean cooler() {\n        if (this.target <= 15) {\n            return false;\n        }\n        this.target--;\n        return true;\n    }\n\n    public int getTarget() {\n        return this.target;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        Thermostat thermostat = new Thermostat(21);\n        UserInterface ui = new UserInterface(scanner, thermostat);\n        ui.start();\n    }\n}\n","hints":["`UserInterface` gets two instance variables, the Scanner and the Thermostat, set in its constructor. The whole `while` loop moves into `public void start()`.","In the moved loop, `scanner` becomes `this.scanner` and `thermostat` becomes `this.thermostat`. `main` keeps its first two lines and then does `UserInterface ui = new UserInterface(scanner, thermostat);` and `ui.start();`."],"tests":[{"name":"Test 1","stdin":"show\nup\nup\ndown\nheat\noff\n","expect":"> Target: 21 degrees\n> Target: 22 degrees\n> Target: 23 degrees\n> Target: 22 degrees\n> Unknown command: heat\n> Thermostat off","hidden":false},{"name":"Test 2","stdin":"up\nup\nup\nup\nup\nup\nup\nup\nshow\noff\n","expect":"> Target: 22 degrees\n> Target: 23 degrees\n> Target: 24 degrees\n> Target: 25 degrees\n> Target: 26 degrees\n> Target: 27 degrees\n> Target: 28 degrees\n> Already at the maximum\n> Target: 28 degrees\n> Thermostat off","hidden":true},{"name":"Test 3","stdin":"","call":"Thermostat cold = new Thermostat(16);\nUserInterface ui = new UserInterface(new Scanner(\"down\\ndown\\ndown\\nshow\\noff\\n\"), cold);\nui.start();\nSystem.out.println(cold.getTarget());\n","expect":"> Target: 15 degrees\n> Already at the minimum\n> Already at the minimum\n> Target: 15 degrees\n> Thermostat off\n15","hidden":true}],"require":[{"pattern":"\\.start\\s*\\(\\s*\\)","message":"`main` starts the user interface with `ui.start()`."}],"forbid":[{"pattern":"\\bclass\\s+Main\\b[\\s\\S]*\\bwhile\\b","message":"The command loop belongs in `start()` now: `main` only creates the objects and starts the user interface."}]},{"task":"A lemonade stand starts the day with 10 cups of lemonade. `LemonadeStand.java` is ready, and so is the `start()` method of `UserInterface.java`. But the user interface has no instance variables or constructor yet, so it doesn't compile. Add them: the constructor takes a `Scanner` and a `LemonadeStand`, and `start()` uses them as `this.scanner` and `this.stand`.\n\nThen write `main`: create the Scanner, a stand with 10 cups and the user interface, and start it. When `start()` returns, print `Sold today: `, the number of cups sold and ` cups`. The stand knows it: ask it with `cupsSold()`. For the input shown, the program prints:\n\n```\n> Sold 3 cups\n> Sold 4 cups\n> Cups left: 3\n> Only 3 cups left\n> Closing the stand\nSold today: 7 cups\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        // Create the objects, start the user interface, and print the cups sold.\n    }\n}\n\n// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    // Write the instance variables and the constructor here.\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"close\")) {\n                System.out.println(\"Closing the stand\");\n                break;\n            }\n            if (command.equals(\"sell\")) {\n                int cups = Integer.valueOf(this.scanner.nextLine());\n                if (this.stand.sell(cups)) {\n                    System.out.println(\"Sold \" + cups + \" cups\");\n                } else {\n                    System.out.println(\"Only \" + this.stand.cupsLeft() + \" cups left\");\n                }\n            } else if (command.equals(\"left\")) {\n                System.out.println(\"Cups left: \" + this.stand.cupsLeft());\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n\n// ==== LemonadeStand.java ====\npublic class LemonadeStand {\n    private int cups;\n    private int sold;\n\n    public LemonadeStand(int cups) {\n        this.cups = cups;\n        this.sold = 0;\n    }\n\n    public boolean sell(int count) {\n        if (count > this.cups) {\n            return false;\n        }\n        this.cups = this.cups - count;\n        this.sold = this.sold + count;\n        return true;\n    }\n\n    public int cupsLeft() {\n        return this.cups;\n    }\n\n    public int cupsSold() {\n        return this.sold;\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        // Create the objects, start the user interface, and print the cups sold.\n        Scanner scanner = new Scanner(System.in);\n        LemonadeStand stand = new LemonadeStand(10);\n        UserInterface ui = new UserInterface(scanner, stand);\n        ui.start();\n        System.out.println(\"Sold today: \" + stand.cupsSold() + \" cups\");\n    }\n}\n\n// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    // Write the instance variables and the constructor here.\n    private Scanner scanner;\n    private LemonadeStand stand;\n\n    public UserInterface(Scanner scanner, LemonadeStand stand) {\n        this.scanner = scanner;\n        this.stand = stand;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"close\")) {\n                System.out.println(\"Closing the stand\");\n                break;\n            }\n            if (command.equals(\"sell\")) {\n                int cups = Integer.valueOf(this.scanner.nextLine());\n                if (this.stand.sell(cups)) {\n                    System.out.println(\"Sold \" + cups + \" cups\");\n                } else {\n                    System.out.println(\"Only \" + this.stand.cupsLeft() + \" cups left\");\n                }\n            } else if (command.equals(\"left\")) {\n                System.out.println(\"Cups left: \" + this.stand.cupsLeft());\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n\n// ==== LemonadeStand.java ====\npublic class LemonadeStand {\n    private int cups;\n    private int sold;\n\n    public LemonadeStand(int cups) {\n        this.cups = cups;\n        this.sold = 0;\n    }\n\n    public boolean sell(int count) {\n        if (count > this.cups) {\n            return false;\n        }\n        this.cups = this.cups - count;\n        this.sold = this.sold + count;\n        return true;\n    }\n\n    public int cupsLeft() {\n        return this.cups;\n    }\n\n    public int cupsSold() {\n        return this.sold;\n    }\n}\n","hints":["The names come from `start()`: it uses `this.scanner` and `this.stand`, so those are the instance variables, a `Scanner` and a `LemonadeStand`. The constructor sets both.","`main` needs `import java.util.Scanner;` at the top. Keep the stand in a variable, give it to the user interface, and after `ui.start();` ask that same stand for `cupsSold()`."],"tests":[{"name":"Test 1","stdin":"sell\n3\nsell\n4\nleft\nsell\n5\nclose\n","expect":"> Sold 3 cups\n> Sold 4 cups\n> Cups left: 3\n> Only 3 cups left\n> Closing the stand\nSold today: 7 cups","hidden":false},{"name":"Test 2","stdin":"close\n","expect":"> Closing the stand\nSold today: 0 cups","hidden":true},{"name":"Test 3","stdin":"sell\n10\nsell\n1\nleft\nlemonade\nclose\n","expect":"> Sold 10 cups\n> Only 0 cups left\n> Cups left: 0\n> Unknown command: lemonade\n> Closing the stand\nSold today: 10 cups","hidden":true},{"name":"Test 4","stdin":"","call":"LemonadeStand stand = new LemonadeStand(4);\nUserInterface ui = new UserInterface(new Scanner(\"sell\\n4\\nsell\\n1\\nclose\\n\"), stand);\nui.start();\nSystem.out.println(stand.cupsSold() + \" \" + stand.cupsLeft());\n","expect":"> Sold 4 cups\n> Only 0 cups left\n> Closing the stand\n4 0","hidden":true}],"require":[{"pattern":"\\.cupsSold\\s*\\(\\s*\\)","message":"After the user interface has finished, ask the stand how many cups it sold with `cupsSold()`."}],"forbid":[]}]}