Java Arena
Step 5 of 7

Many objects, and arrows both ways

A star for a list

At a music festival, each stage has a lineup of acts. Stage keeps them in a list:

public class Stage {
    private String name;
    private ArrayList<Act> acts;

    // the constructor and methods
}

The list holds Act objects, so it's drawn as an arrow to Act, like a field of type Act would be. A star at the arrowhead says that a Stage has any number of them:

The diagram as text
  • Act, a class
    • private field name: String
    • private field minutes: int
    • public constructor Act(name: String, minutes: int)
    • public method getMinutes(): int
    • public method toString(): String
  • Stage, a class
    • private field name: String
    • public constructor Stage(name: String)
    • public method add(act: Act): void
    • public method totalMinutes(): int
    • public method getActs(): ArrayList<Act>

Connections:

  • Each Stage has any number of Act objects (acts).
  • * means any number, zero included: a new stage has an empty lineup.
  • The list isn't in Stage's box, just as a single Act field wouldn't be. The arrow and its star stand for private ArrayList<Act> acts;, which the constructor creates.
  • The methods that work with the list are in the box as usual. A list type is written as in Java: getActs(): ArrayList<Act>.
  • Other multiplicities you may meet: 1..* for one or more, and a range such as 2..4.
  • A list of Strings or of numbers stays in the box as a field, such as -tags: ArrayList<String>. Arrows are for the diagram's own classes.
Main.java
public class Main {
    public static void main(String[] args) {
        Stage tent = new Stage("Blue Tent");
        tent.add(new Act("The Low Tides", 45));
        tent.add(new Act("Mira Solen", 30));
        System.out.println(tent.getActs());
        System.out.println(tent.totalMinutes());
    }
}
Act.java
public class Act {
    private String name;
    private int minutes;

    public Act(String name, int minutes) {
        this.name = name;
        this.minutes = minutes;
    }

    public int getMinutes() {
        return this.minutes;
    }

    @Override
    public String toString() {
        return this.name + " (" + this.minutes + " min)";
    }
}
Stage.java
import java.util.ArrayList;

public class Stage {
    private String name;
    private ArrayList<Act> acts;

    public Stage(String name) {
        this.name = name;
        this.acts = new ArrayList<>();
    }

    public void add(Act act) {
        this.acts.add(act);
    }

    public int totalMinutes() {
        int total = 0;
        for (Act act : this.acts) {
            total += act.getMinutes();
        }
        return total;
    }

    public ArrayList<Act> getActs() {
        return this.acts;
    }
}
Output
[The Low Tides (45 min), Mira Solen (30 min)]
75

You'll also see the list created right where the field is declared, instead of in the constructor:

public class Stage {
    private String name;
    private ArrayList<Act> acts = new ArrayList<>();

    public Stage(String name) {
        this.name = name;
    }

    // the methods as before
}

It does the same thing: each new Stage gets an empty list of its own, and the diagram is the same. Any instance variable can get its first value this way, for example an array: private int[] scores = new int[5];.

A multiplicity can also sit at the start of an arrow. It then says how many objects of the first class can share one object at the head. Step 4's performances, drawn with both numbers:

The diagram as text
  • Play, a class
    • private field title: String
  • Performance, a class
    • private field date: String

Connections:

  • Each Performance has one Play object; each Play belongs to any number of Performance objects.

Each Performance has one Play, and a Play can have any number of performances, even though a Play doesn't know them: the arrow still points one way.

Both ways

The acts above don't know which stage they're on. If the program needs that, say to print each act with its stage, Act gets a field of type Stage, and then the two classes know each other. The diagram draws that as a line without an arrowhead, with a multiplicity at each end:

The diagram as text
  • Stage, a class
    • private field name: String
    • public constructor Stage(name: String)
    • public method add(act: Act): void
    • public method getName(): String
  • Act, a class
    • private field name: String
    • private field minutes: int
    • public constructor Act(name: String, minutes: int)
    • public method setStage(stage: Stage): void
    • public method toString(): String

Connections:

  • Stage and Act know each other: each Stage has any number of Act objects, and each Act has at most one Stage object.

Read each end's number as "how many of these": each Stage has any number of Acts (the * at Act's end), and each Act is on at most one Stage (the 0..1 at Stage's end: none until it's added).

In code, a connection both ways is two fields: Stage's list of acts, and Act's stage. They have to agree: when an act goes on a stage, the act must learn its stage too. The usual way is to let one method do both. Inside a method, this is the object the method was called on, so act.setStage(this) gives the act this very stage:

Main.java
public class Main {
    public static void main(String[] args) {
        Stage tent = new Stage("Blue Tent");
        Act tides = new Act("The Low Tides", 45);
        System.out.println(tides);
        tent.add(tides);
        System.out.println(tides);
    }
}
Stage.java
import java.util.ArrayList;

public class Stage {
    private String name;
    private ArrayList<Act> acts;

    public Stage(String name) {
        this.name = name;
        this.acts = new ArrayList<>();
    }

    public void add(Act act) {
        this.acts.add(act);
        act.setStage(this);
    }

    public String getName() {
        return this.name;
    }
}
Act.java
public class Act {
    private String name;
    private int minutes;
    private Stage stage;

    public Act(String name, int minutes) {
        this.name = name;
        this.minutes = minutes;
        this.stage = null;
    }

    public void setStage(Stage stage) {
        this.stage = stage;
    }

    @Override
    public String toString() {
        if (this.stage == null) {
            return this.name + ", " + this.minutes + " min, no stage yet";
        }
        return this.name + ", " + this.minutes + " min, " + this.stage.getName();
    }
}
Output
The Low Tides, 45 min, no stage yet
The Low Tides, 45 min, Blue Tent

A connection both ways costs more than an arrow: two fields to keep in step, and a change that updates one side and forgets the other leaves them disagreeing. So draw, and write, a one-way arrow unless the program really needs both directions.

Your task

Challenge 1 of 3

The ward keeps its patients in a list. Patient.java is ready. Write the class Ward in Ward.java, as the diagram shows:

The diagram as text
  • Patient, a class
    • private field name: String
    • private field room: int
    • private field temperature: double
    • public constructor Patient(name: String, room: int, temperature: double)
    • public method getName(): String
    • public method getTemperature(): double
    • public method toString(): String
  • Ward, a class
    • private field name: String
    • public constructor Ward(name: String)
    • public method admit(patient: Patient): void
    • public method withFever(): ArrayList<Patient>
    • public method toString(): String

Connections:

  • Each Ward has any number of Patient objects (patients).
  • A new ward has no patients. admit adds a patient to the ward.
  • withFever returns a new list of the patients whose temperature is 38.0 or more, in the order they were admitted.
  • toString returns Ward 5B: 3 patients, with the ward's own name and number of patients.

The check runs:

Ward ward = new Ward("Ward 5B");
ward.admit(new Patient("Ines Moreau", 12, 38.4));
ward.admit(new Patient("Oskar Lund", 12, 36.9));
ward.admit(new Patient("Mei Tan", 14, 38.0));
System.out.println(ward);
for (Patient patient : ward.withFever()) {
    System.out.println(patient.getName());
}

and expects:

Ward 5B: 3 patients
Ines Moreau
Mei Tan

Challenge 2

The festival moves The Low Tides from the Blue Tent to the Main Field. Stage and Act are the classes of the lesson's connection both ways, and Stage has one more method, count(), which returns the number of acts in its list:

The diagram as text
  • Stage, a class
    • private field name: String
    • public constructor Stage(name: String)
    • public method add(act: Act): void
    • public method getName(): String
    • public method count(): int
  • Act, a class
    • private field name: String
    • private field minutes: int
    • public constructor Act(name: String, minutes: int)
    • public method setStage(stage: Stage): void
    • public method toString(): String

Connections:

  • Stage and Act know each other: each Stage has any number of Act objects, and each Act has at most one Stage object.

What does this program print?

Challenge 3

A garden center sells seedlings in trays, and a tray has room for at most 6 of them. Write both classes of this diagram, Seedling in Seedling.java and Tray in Tray.java:

The diagram as text
  • Seedling, a class
    • private field name: String
    • private field price: int
    • public constructor Seedling(name: String, price: int)
    • public method getPrice(): int
    • public method toString(): String
  • Tray, a class
    • public constructor Tray()
    • public method add(seedling: Seedling): boolean
    • public method total(): int
    • public method toString(): String

Connections:

  • Each Tray has 0 to 6 Seedling objects (seedlings).
  • A seedling's toString returns Basil (3 dollars), with its own name and price.
  • A new tray is empty. add puts the seedling in the tray and returns true, unless the tray already has 6 seedlings: then it returns false and adds nothing.
  • total returns the prices of the tray's seedlings added up.
  • A tray's toString returns 3 seedlings, 11 dollars.

The check runs:

Tray tray = new Tray();
tray.add(new Seedling("Basil", 3));
tray.add(new Seedling("Tomato", 4));
tray.add(new Seedling("Mint", 4));
System.out.println(tray);
System.out.println(new Seedling("Thyme", 2));

and expects:

3 seedlings, 11 dollars
Thyme (2 dollars)