Java Arena
Step 1 of 5

Turning a program into objects

This module is about designing classes: deciding what a class should hold and do, and giving it several constructors, or several methods of the same name. It starts with why a class of your own is worth writing at all.

A program of plain variables

Here's a program that follows two people's steps for a day, written the way you'd have written it before module 17. The goal is 10000 steps a day.

String firstName = "Noor";
int firstSteps = 0;
String secondName = "Theo";
int secondSteps = 0;

firstSteps = firstSteps + 6200;
secondSteps = secondSteps + 3100;
firstSteps = firstSteps + 4500;

if (firstSteps >= 10000) {
    System.out.println(firstName + ": " + firstSteps + " steps, goal reached");
} else {
    System.out.println(firstName + ": " + firstSteps + " steps");
}
if (secondSteps >= 10000) {
    System.out.println(secondName + ": " + secondSteps + " steps, goal reached");
} else {
    System.out.println(secondName + ": " + secondSteps + " steps");
}
Output
Noor: 10700 steps, goal reached
Theo: 3100 steps

It works, but look at what it takes:

  • Four variables, and only their names say that firstName and firstSteps belong together.
  • The goal check is written twice. To change the goal, you have to find and change both copies.
  • A third person means two more variables and a copy of every line that uses them. Write firstSteps in one of the copies where you meant secondSteps, and the program adds the steps to the wrong person, without any error message.

The same program with objects

Each person has a name and a number of steps, and the same goal applies to everyone. That's a class: a StepCounter holds one person's name and steps, and knows the goal.

Main.java
public class Main {
    public static void main(String[] args) {
        StepCounter noor = new StepCounter("Noor");
        StepCounter theo = new StepCounter("Theo");

        noor.walk(6200);
        theo.walk(3100);
        noor.walk(4500);

        System.out.println(noor);
        System.out.println(theo);
    }
}
StepCounter.java
public class StepCounter {
    private String name;
    private int steps;

    public StepCounter(String name) {
        this.name = name;
        this.steps = 0;
    }

    public void walk(int steps) {
        this.steps = this.steps + steps;
    }

    public String toString() {
        if (this.steps >= 10000) {
            return this.name + ": " + this.steps + " steps, goal reached";
        }
        return this.name + ": " + this.steps + " steps";
    }
}
Output
Noor: 10700 steps, goal reached
Theo: 3100 steps

The output is the same, but the program reads differently:

  • main tells what happens in the words of the problem: Noor walks 6200 steps, Theo walks 3100. How the steps are added up is the class's business.
  • Each person's name and steps travel together in one object, so they can't get mixed up with someone else's.
  • The goal is written once, in toString. Change it there, and it changes for everyone.
  • A third person is one more line: StepCounter maya = new StepCounter("Maya");.

This is the idea behind object-oriented programming: a program is built from objects, and each object looks after its own data and the rules that go with it. A class stands for one idea of the problem (here, a step counter), its instance variables are what each object must remember, and its methods are what can be done with it. The rest of the program only calls the methods, just as it uses an ArrayList without knowing how it works inside.

A class is worth it even when there's only one object. A program about a single person is still easier to read with a StepCounter, because the names of the class and its methods say what the variables are for.

Your task

Challenge 1 of 3

In a game, a hero starts with 100 health. A hit takes health away, but never below 0, and healing gives health back, but never above 100. Main.java is ready and uses a Hero object. Write the class in Hero.java:

  • Hero(String name) makes a hero with 100 health.
  • hit(int damage) takes damage off the health. The health doesn't go below 0.
  • heal(int amount) adds amount to the health. The health doesn't go above 100.
  • toString() returns the name and the health, as in the output below.

The program prints:

Aria, health 90
Aria, health 100
Aria, health 0

Challenge 2

This program counts the visitors at the two gates of a zoo. It reads a line for each visitor, north or south, until the line end, and then prints both counts. Any other line is skipped. It keeps the counts in plain variables. Gate.java holds a class that does the counting: rewrite main so it uses two Gate objects instead of the two counters, gives each visitor to the right gate with pass(), and prints the gates. For the input north, south, north and end, one per line, the program still prints:

North gate: 2
South gate: 1

Challenge 3

What does this program print? It uses the Hero class from the first challenge, with two heroes.