{"id":"class-design-designing","slug":"designing-a-class","title":"Designing a class","text":"Writing a class starts before the code. From a description of the problem, you decide what the class holds and what it can do. Take this one:\n\n> A train has a name and a number of cars. Every car seats 60 people. Cars can be added to the train and taken off it, but a train always keeps at least one car. We want to know how many seats a train has, and to print it like `Coast Line: 3 cars, 180 seats`.\n\nFour questions lead from a description like this to a class.\n\n**1. What must each object remember?** The answer gives the instance variables. A train must remember its name and its number of cars. They differ from train to train, and the cars can change: `private String name;` and `private int cars;`.\n\nThe seats are different: they follow from the number of cars. If the class kept them in a variable of their own, every method that changes the cars would also have to update the seats, and a single forgotten line would leave a train with 3 cars and 240 seats. A value that can be worked out from the others is best worked out by a method, each time it's needed. The 60 seats of a car are the same for every train, so that method can simply use the number 60.\n\n**2. What does a new object need?** The answer gives the constructor's parameters. A new train needs its name. The description doesn't say how many cars a train starts with, so let it start with one: `public Train(String name)`.\n\n**3. What can be done with it, and what do we want to know?** The answers give the methods. The things that are done, adding cars and taking them off, become methods that change the object: `addCar()` and `removeCar()`. The rule \"at least one car\" goes into `removeCar`, the only place where the cars go down. The question \"how many seats?\" becomes a method that returns a value: `seats()`.\n\n**4. How should it look as text?** The answer goes in `toString`, which can call `seats()` instead of multiplying again.\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Train train = new Train(\"Coast Line\");\n        train.addCar();\n        train.addCar();\n        System.out.println(train);\n        train.removeCar();\n        train.removeCar();\n        train.removeCar();\n        System.out.println(train.seats());\n    }\n}\n// ==== Train.java ====\npublic class Train {\n    private String name;\n    private int cars;\n\n    public Train(String name) {\n        this.name = name;\n        this.cars = 1;\n    }\n\n    public void addCar() {\n        this.cars = this.cars + 1;\n    }\n\n    public void removeCar() {\n        if (this.cars > 1) {\n            this.cars = this.cars - 1;\n        }\n    }\n\n    public int seats() {\n        return this.cars * 60;\n    }\n\n    public String toString() {\n        return this.name + \": \" + this.cars + \" cars, \" + this.seats() + \" seats\";\n    }\n}\n```\n\n```output\nCoast Line: 3 cars, 180 seats\n60\n```\n\n- `main` doesn't need to know that the seats are worked out rather than stored: it just asks `seats()`.\n- `toString` calls the object's own `seats()`, so \"60 seats a car\" is written in one place only.\n- `removeCar` keeps the train at one car at least, whatever `main` does. The third `removeCar()` above changes nothing.\n\nDesigns can differ. Another program might need a constructor that also takes the number of cars, or a method that tells whether a group fits on the train. Start with what the description asks for: a method that nothing calls is only more code to read.\n","task":"Here's a description. *A garden bed is a rectangle, with a length and a width in whole meters. Every square meter has room for 4 plants. We want to know a bed's area and how many plants it has room for, and to print it like `3 x 2 m, room for 24 plants`.*\n\nWrite the class `GardenBed`, with the constructor `GardenBed(int length, int width)` and the methods `area()`, `room()` and `toString()`. Keep only what a bed must remember in instance variables. `room()` should use `area()`, and `toString()` should use `room()`. The check creates `new GardenBed(3, 2)` and prints its area and then the bed:\n\n```\n6\n3 x 2 m, room for 24 plants\n```\n","kind":"code","seed":"// ==== GardenBed.java ====\npublic class GardenBed {\n\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        GardenBed bed = new GardenBed(3, 2);\n        System.out.println(bed.area());\n        System.out.println(bed);\n    }\n}\n","solution":"// ==== GardenBed.java ====\npublic class GardenBed {\n    private int length;\n    private int width;\n\n    public GardenBed(int length, int width) {\n        this.length = length;\n        this.width = width;\n    }\n\n    public int area() {\n        return this.length * this.width;\n    }\n\n    public int room() {\n        return this.area() * 4;\n    }\n\n    public String toString() {\n        return this.length + \" x \" + this.width + \" m, room for \" + this.room() + \" plants\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        GardenBed bed = new GardenBed(3, 2);\n        System.out.println(bed.area());\n        System.out.println(bed);\n    }\n}\n","hints":["A bed must remember its length and its width: two private `int` instance variables. The area and the room follow from them, so they're methods: `public int area()` and `public int room()`.","`area()` returns `this.length * this.width`, and `room()` returns `this.area() * 4`. `toString` builds the text with `this.room()`."],"tests":[{"name":"Test 1","stdin":"","call":"GardenBed bed = new GardenBed(3, 2);\nSystem.out.println(bed.area());\nSystem.out.println(bed);\n","expect":"6\n3 x 2 m, room for 24 plants","hidden":false},{"name":"Test 2","stdin":"","call":"GardenBed bed = new GardenBed(5, 4);\nSystem.out.println(bed.area());\nSystem.out.println(bed.room());\nSystem.out.println(bed);\n","expect":"20\n80\n5 x 4 m, room for 80 plants","hidden":true},{"name":"Test 3","stdin":"","call":"GardenBed small = new GardenBed(1, 1);\nGardenBed strip = new GardenBed(12, 1);\nSystem.out.println(strip);\nSystem.out.println(small);\n","expect":"12 x 1 m, room for 48 plants\n1 x 1 m, room for 4 plants","hidden":true}],"require":[{"pattern":"\\barea\\s*\\(\\s*\\)","min":3,"message":"Write `area()`, and let `room()` call it instead of multiplying the length and the width again."},{"pattern":"\\broom\\s*\\(\\s*\\)","min":2,"message":"Write `room()`, and let `toString()` call it."}],"forbid":[{"pattern":"\\bprivate\\s+int\\s+(area|room)\\b","message":"The area and the room follow from the length and the width: work them out in `area()` and `room()` instead of storing them in instance variables."}],"more":[{"task":"What does this program print? It uses the `Train` class from the lesson.\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Train morning = new Train(\"Morning Express\");\n        Train night = new Train(\"Night Owl\");\n        morning.addCar();\n        night.removeCar();\n        night.addCar();\n        night.addCar();\n        morning.addCar();\n        morning.removeCar();\n        System.out.println(morning);\n        System.out.println(night.seats());\n    }\n}\n// ==== Train.java ====\npublic class Train {\n    private String name;\n    private int cars;\n\n    public Train(String name) {\n        this.name = name;\n        this.cars = 1;\n    }\n\n    public void addCar() {\n        this.cars = this.cars + 1;\n    }\n\n    public void removeCar() {\n        if (this.cars > 1) {\n            this.cars = this.cars - 1;\n        }\n    }\n\n    public int seats() {\n        return this.cars * 60;\n    }\n\n    public String toString() {\n        return this.name + \": \" + this.cars + \" cars, \" + this.seats() + \" seats\";\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Train morning = new Train(\"Morning Express\");\n        Train night = new Train(\"Night Owl\");\n        morning.addCar();\n        night.removeCar();\n        night.addCar();\n        night.addCar();\n        morning.addCar();\n        morning.removeCar();\n        System.out.println(morning);\n        System.out.println(night.seats());\n    }\n}\n// ==== Train.java ====\npublic class Train {\n    private String name;\n    private int cars;\n\n    public Train(String name) {\n        this.name = name;\n        this.cars = 1;\n    }\n\n    public void addCar() {\n        this.cars = this.cars + 1;\n    }\n\n    public void removeCar() {\n        if (this.cars > 1) {\n            this.cars = this.cars - 1;\n        }\n    }\n\n    public int seats() {\n        return this.cars * 60;\n    }\n\n    public String toString() {\n        return this.name + \": \" + this.cars + \" cars, \" + this.seats() + \" seats\";\n    }\n}\n","hints":["Every train starts with one car. The morning train gets two cars added and one taken off.","The night train can't lose its only car, so its `removeCar()` changes nothing. Then it gets two cars added, and `seats()` multiplies its cars by 60."],"tests":[{"name":"Output","stdin":"","expect":"Morning Express: 2 cars, 120 seats\n180","hidden":false}],"require":[],"forbid":[],"lines":["Morning Express: 2 cars, 120 seats","180"]},{"task":"A parcel locker at a station has a number of compartments, each for one parcel. Write the class `ParcelLocker`:\n\n- `ParcelLocker(int compartments)` makes an empty locker with that many compartments.\n- `free()` returns how many compartments are empty.\n- `store()` puts a parcel in an empty compartment and returns `true`. When no compartment is free, it returns `false` and nothing changes. Use `free()` to check.\n- `pickUp()` takes a parcel out. When the locker is empty, nothing changes.\n- `toString()` returns how many compartments are in use, as in the output below.\n\nDecide the instance variables yourself: what must a locker remember? The check makes a locker of 2 compartments, tries to store three parcels (printing what `store()` returns each time), prints the locker, picks up a parcel and prints `free()`:\n\n```\ntrue\ntrue\nfalse\n2 of 2 compartments in use\n1\n```\n","kind":"code","seed":"// ==== ParcelLocker.java ====\npublic class ParcelLocker {\n\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        ParcelLocker locker = new ParcelLocker(2);\n        System.out.println(locker.store());\n        System.out.println(locker.store());\n        System.out.println(locker.store());\n        System.out.println(locker);\n        locker.pickUp();\n        System.out.println(locker.free());\n    }\n}\n","solution":"// ==== ParcelLocker.java ====\npublic class ParcelLocker {\n    private int compartments;\n    private int parcels;\n\n    public ParcelLocker(int compartments) {\n        this.compartments = compartments;\n        this.parcels = 0;\n    }\n\n    public int free() {\n        return this.compartments - this.parcels;\n    }\n\n    public boolean store() {\n        if (this.free() == 0) {\n            return false;\n        }\n        this.parcels = this.parcels + 1;\n        return true;\n    }\n\n    public void pickUp() {\n        if (this.parcels > 0) {\n            this.parcels = this.parcels - 1;\n        }\n    }\n\n    public String toString() {\n        return this.parcels + \" of \" + this.compartments + \" compartments in use\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        ParcelLocker locker = new ParcelLocker(2);\n        System.out.println(locker.store());\n        System.out.println(locker.store());\n        System.out.println(locker.store());\n        System.out.println(locker);\n        locker.pickUp();\n        System.out.println(locker.free());\n    }\n}\n","hints":["A locker must remember how many compartments it has and how many parcels are in it. The free compartments follow from those two, so `free()` works them out: `return this.compartments - this.parcels;`.","`store()` starts with `if (this.free() == 0) { return false; }`. After that there's room, so it adds a parcel and returns `true`. `pickUp()` takes one off only when there's at least one."],"tests":[{"name":"Test 1","stdin":"","call":"ParcelLocker locker = new ParcelLocker(2);\nSystem.out.println(locker.store());\nSystem.out.println(locker.store());\nSystem.out.println(locker.store());\nSystem.out.println(locker);\nlocker.pickUp();\nSystem.out.println(locker.free());\n","expect":"true\ntrue\nfalse\n2 of 2 compartments in use\n1","hidden":false},{"name":"Test 2","stdin":"","call":"ParcelLocker locker = new ParcelLocker(4);\nSystem.out.println(locker);\nSystem.out.println(locker.free());\nlocker.pickUp();\nSystem.out.println(locker.free());\nSystem.out.println(locker.store());\nSystem.out.println(locker);\n","expect":"0 of 4 compartments in use\n4\n4\ntrue\n1 of 4 compartments in use","hidden":true},{"name":"Test 3","stdin":"","call":"ParcelLocker locker = new ParcelLocker(1);\nSystem.out.println(locker.store());\nSystem.out.println(locker.store());\nlocker.pickUp();\nlocker.pickUp();\nSystem.out.println(locker.store());\nSystem.out.println(locker);\n","expect":"true\nfalse\ntrue\n1 of 1 compartments in use","hidden":true}],"require":[{"pattern":"\\bfree\\s*\\(\\s*\\)","min":3,"message":"Write `free()`, and let `store()` call it to check for an empty compartment."}],"forbid":[]}]}