{"id":"paradigms-objects","slug":"with-objects","title":"The same program with objects","text":"Here's the reading program of the previous step once more, written with an object. The book's data, and the rule that guards it, move into a class, `Book`. `main` only creates a book and uses it:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Book book = new Book(\"The Salt Road\", 240);\n        book.read(60);\n        book.read(100);\n        System.out.println(book);\n\n        book.read(120);\n        System.out.println(book);\n    }\n}\n// ==== Book.java ====\npublic class Book {\n    private String title;\n    private int pages;\n    private int page;\n\n    public Book(String title, int pages) {\n        this.title = title;\n        this.pages = pages;\n        this.page = 0;\n    }\n\n    public void read(int count) {\n        this.page = this.page + count;\n        if (this.page > this.pages) {\n            this.page = this.pages;\n        }\n    }\n\n    public String toString() {\n        int percent = 100 * this.page / this.pages;\n        return this.title + \": page \" + this.page + \" of \" + this.pages + \", \" + percent + \"% read\";\n    }\n}\n```\n\n```output\nThe Salt Road: page 160 of 240, 66% read\nThe Salt Road: page 240 of 240, 100% read\n```\n\nIt prints exactly what the procedural version printed. Here's what moved where:\n\n- The three local variables of `main` became the instance variables of `Book`. The data that belongs together is now in one object, and it's `private`, so only the code of `Book` can change it.\n- `read` takes one parameter, the number of pages read. It finds the rest in its own object, as `this.page` and `this.pages`. It changes the object itself and returns nothing, so there's no result to forget to store.\n- `printProgress` became `toString`, which builds the same line from the object's own data.\n- The rule \"not past the last page\" is still in `read`, and now nothing can get around it. `book.page = 900;` in `main` doesn't compile, because `page` is private: javac says `page has private access in Book`. The only way to move the bookmark is `read`.\n- `main` reads like a description of what happens: a book, 60 pages read, then 100 more.\n\n### What each version makes easy\n\nNeither version is wrong. They print the same lines, and each makes different things easy:\n\n| | Procedural | Object-oriented |\n| --- | --- | --- |\n| Where the data is | local variables in `main` | instance variables of an object |\n| How a method gets the data | as parameters, one by one | from its own object, with `this` |\n| How a change is kept | the method returns the new value, and the caller stores it | the method changes the object |\n| Who can get around the rule | any code that has the variables | only the code of the class |\n| A second book | three more variables | one more `new Book(...)` |\n\n- The procedural version is shorter: no class, no constructor, no `this`. It reads from top to bottom in one file, and every value a method uses is right there in its call. For a small program that runs once from start to end, that's often the simplest choice.\n- The object version has more lines, but each part has one job. The book's data and its rule are in one place, and no other code can get around the rule. As the program grows, with more books or more things to do with a book, `main` stays short and the rules stay in `Book`.\n\n### Java and paradigms\n\nJava is mainly an object-oriented language: every method belongs to a class, and even `main` sits in the class `Main`. But the code inside the methods is usually procedural: statements that run one after another, with ifs and loops, just as in module 1. A program made only of `main` and static methods, like the one in the previous step, is a procedural program that happens to sit in a class. So in Java, the real question is how much of a program to organize into objects. The last step of this module comes back to that.\n","task":"Here's the board game of the previous step, with an object. `Main.java` is ready. Write the class in `Piece.java`:\n\n- `Piece(int lastSquare)`: a piece on square 1, on a board whose last square is `lastSquare`.\n- `move(int steps)`: moves the piece by `steps` squares, but never past the last square, and never below square 1.\n- `getSquare()`: returns the square the piece is on.\n\nThe program prints:\n\n```\nSquare 6\nSquare 30\nSquare 1\n```\n","kind":"code","seed":"// ==== Piece.java ====\npublic class Piece {\n\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Piece piece = new Piece(30);\n        piece.move(5);\n        System.out.println(\"Square \" + piece.getSquare());\n        piece.move(28);\n        System.out.println(\"Square \" + piece.getSquare());\n        piece.move(-40);\n        System.out.println(\"Square \" + piece.getSquare());\n    }\n}\n","solution":"// ==== Piece.java ====\npublic class Piece {\n    private int lastSquare;\n    private int square;\n\n    public Piece(int lastSquare) {\n        this.lastSquare = lastSquare;\n        this.square = 1;\n    }\n\n    public void move(int steps) {\n        this.square = this.square + steps;\n        if (this.square > this.lastSquare) {\n            this.square = this.lastSquare;\n        }\n        if (this.square < 1) {\n            this.square = 1;\n        }\n    }\n\n    public int getSquare() {\n        return this.square;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Piece piece = new Piece(30);\n        piece.move(5);\n        System.out.println(\"Square \" + piece.getSquare());\n        piece.move(28);\n        System.out.println(\"Square \" + piece.getSquare());\n        piece.move(-40);\n        System.out.println(\"Square \" + piece.getSquare());\n    }\n}\n","hints":["The piece remembers two numbers, in private instance variables: the last square, given to the constructor, and the square it's on, which starts at 1.","`move` is the static `move` of the previous step, working on the object: add `steps` to `this.square`, then set it to `this.lastSquare` if it's past that, and to 1 if it's below 1."],"tests":[{"name":"The program","stdin":"","expect":"Square 6\nSquare 30\nSquare 1","hidden":false},{"name":"Test 2","stdin":"","call":"Piece big = new Piece(50);\nPiece small = new Piece(10);\nbig.move(20);\nsmall.move(20);\nSystem.out.println(big.getSquare() + \" \" + small.getSquare());\nbig.move(-30);\nsmall.move(-3);\nSystem.out.println(big.getSquare() + \" \" + small.getSquare());\n","expect":"21 10\n1 7","hidden":true}],"require":[],"forbid":[],"more":[{"task":"At a quiz night, a team gets 10 points for a right answer and loses 5 for a wrong one, but its score never goes below 0. The program in `Main.java` keeps two teams' scores procedurally. Rewrite it with objects. Write the class in `Team.java`:\n\n- `Team(String name)`: a team with 0 points.\n- `answer(boolean right)`: adds 10 points for a right answer, and takes 5 off for a wrong one, but never below 0.\n- `toString()`: returns the name and the points, like `Foxes: 15 points`.\n\nThen change `main` so that it uses two Team objects instead of the four variables and the static method, which it doesn't need any more. The program prints what it does now:\n\n```\nFoxes: 15 points\nOwls: 0 points\n```\n","kind":"code","seed":"// ==== Team.java ====\npublic class Team {\n\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        String firstName = \"Foxes\";\n        int firstPoints = 0;\n        String secondName = \"Owls\";\n        int secondPoints = 0;\n\n        firstPoints = answer(firstPoints, true);\n        secondPoints = answer(secondPoints, false);\n        firstPoints = answer(firstPoints, false);\n        secondPoints = answer(secondPoints, true);\n        firstPoints = answer(firstPoints, true);\n        secondPoints = answer(secondPoints, false);\n        secondPoints = answer(secondPoints, false);\n\n        System.out.println(firstName + \": \" + firstPoints + \" points\");\n        System.out.println(secondName + \": \" + secondPoints + \" points\");\n    }\n\n    public static int answer(int points, boolean right) {\n        if (right) {\n            return points + 10;\n        }\n        points = points - 5;\n        if (points < 0) {\n            points = 0;\n        }\n        return points;\n    }\n}\n","solution":"// ==== Team.java ====\npublic class Team {\n    private String name;\n    private int points;\n\n    public Team(String name) {\n        this.name = name;\n        this.points = 0;\n    }\n\n    public void answer(boolean right) {\n        if (right) {\n            this.points = this.points + 10;\n        } else {\n            this.points = this.points - 5;\n            if (this.points < 0) {\n                this.points = 0;\n            }\n        }\n    }\n\n    public String toString() {\n        return this.name + \": \" + this.points + \" points\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Team foxes = new Team(\"Foxes\");\n        Team owls = new Team(\"Owls\");\n\n        foxes.answer(true);\n        owls.answer(false);\n        foxes.answer(false);\n        owls.answer(true);\n        foxes.answer(true);\n        owls.answer(false);\n        owls.answer(false);\n\n        System.out.println(foxes);\n        System.out.println(owls);\n    }\n}\n","hints":["The name and the points of one team become the private instance variables of Team. `answer` does what the static method did, but on `this.points`, and it returns nothing.","In `main`, create `Team foxes = new Team(\"Foxes\");` and one for the Owls, and turn each line like `firstPoints = answer(firstPoints, true);` into `foxes.answer(true);`. `System.out.println(foxes);` uses toString."],"tests":[{"name":"The program","stdin":"","expect":"Foxes: 15 points\nOwls: 0 points","hidden":false},{"name":"Test 2","stdin":"","call":"Team bees = new Team(\"Bees\");\nbees.answer(false);\nbees.answer(true);\nbees.answer(true);\nbees.answer(false);\nTeam ants = new Team(\"Ants\");\nants.answer(true);\nSystem.out.println(bees);\nSystem.out.println(ants + \" / \" + bees);\n","expect":"Bees: 15 points\nAnts: 10 points / Bees: 15 points","hidden":true}],"require":[{"pattern":"new\\s+Team\\s*\\(","min":2,"message":"Create two Team objects in `main`, one for each team."}],"forbid":[{"pattern":"\\bstatic\\s+int\\s+answer\\b","message":"The rule now lives in Team, so `main` doesn't need the static method `answer` any more."}]},{"task":"Going the other way helps you see both styles. In a board game, each turn has a time limit. `TurnTimer.java` is an object version: `tick(int seconds)` counts the seconds down, never below 0, and `isOver()` tells when the time is up. `main` uses it. Leave `TurnTimer.java` as it is, to compare.\n\nRewrite `main` procedurally, without the TurnTimer class. Keep the seconds left in an `int` variable in `main`, and write two static methods in `Main`:\n\n- `tick(int seconds, int passed)` returns the seconds left after `passed` more seconds, but never below 0.\n- `isOver(int seconds)` returns `true` when no seconds are left, and `false` otherwise.\n\nThe program prints what it does now:\n\n```\n35 seconds left\n15 seconds left\nTime's up!\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        TurnTimer timer = new TurnTimer(60);\n        timer.tick(25);\n        System.out.println(timer.getSeconds() + \" seconds left\");\n        timer.tick(20);\n        System.out.println(timer.getSeconds() + \" seconds left\");\n        timer.tick(30);\n        if (timer.isOver()) {\n            System.out.println(\"Time's up!\");\n        } else {\n            System.out.println(timer.getSeconds() + \" seconds left\");\n        }\n    }\n}\n\n// ==== TurnTimer.java ====\npublic class TurnTimer {\n    private int seconds;\n\n    public TurnTimer(int seconds) {\n        this.seconds = seconds;\n    }\n\n    public void tick(int passed) {\n        this.seconds = this.seconds - passed;\n        if (this.seconds < 0) {\n            this.seconds = 0;\n        }\n    }\n\n    public boolean isOver() {\n        return this.seconds == 0;\n    }\n\n    public int getSeconds() {\n        return this.seconds;\n    }\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        int seconds = 60;\n        seconds = tick(seconds, 25);\n        System.out.println(seconds + \" seconds left\");\n        seconds = tick(seconds, 20);\n        System.out.println(seconds + \" seconds left\");\n        seconds = tick(seconds, 30);\n        if (isOver(seconds)) {\n            System.out.println(\"Time's up!\");\n        } else {\n            System.out.println(seconds + \" seconds left\");\n        }\n    }\n\n    public static int tick(int seconds, int passed) {\n        seconds = seconds - passed;\n        if (seconds < 0) {\n            seconds = 0;\n        }\n        return seconds;\n    }\n\n    public static boolean isOver(int seconds) {\n        return seconds == 0;\n    }\n}\n\n// ==== TurnTimer.java ====\npublic class TurnTimer {\n    private int seconds;\n\n    public TurnTimer(int seconds) {\n        this.seconds = seconds;\n    }\n\n    public void tick(int passed) {\n        this.seconds = this.seconds - passed;\n        if (this.seconds < 0) {\n            this.seconds = 0;\n        }\n    }\n\n    public boolean isOver() {\n        return this.seconds == 0;\n    }\n\n    public int getSeconds() {\n        return this.seconds;\n    }\n}\n","hints":["The object's instance variable becomes a local variable of `main`: `int seconds = 60;`. Each `timer.tick(25);` becomes `seconds = tick(seconds, 25);`, which stores the answer.","`tick` gets the seconds as a parameter, takes `passed` off, sets the result to 0 if it's below 0, and returns it. `isOver(int seconds)` returns `seconds == 0`."],"tests":[{"name":"The program","stdin":"","expect":"35 seconds left\n15 seconds left\nTime's up!","hidden":false},{"name":"System.out.println(tick(60, 25) + \" \" + tick(10, 25) + \" \" + tick(0, 5) + \" \" + tick(30, 30));","stdin":"","call":"System.out.println(tick(60, 25) + \" \" + tick(10, 25) + \" \" + tick(0, 5) + \" \" + tick(30, 30));\n","expect":"35 0 0 0","hidden":true},{"name":"System.out.println(isOver(0) + \" \" + isOver(1) + \" \" + isOver(45));","stdin":"","call":"System.out.println(isOver(0) + \" \" + isOver(1) + \" \" + isOver(45));\n","expect":"true false false","hidden":true}],"require":[],"forbid":[{"pattern":"\\bnew\\s+TurnTimer\\s*\\(","message":"Write `main` without the TurnTimer class: keep the seconds in an `int` variable, and use your static methods."}]}]}