Java Arena
Step 9 of 9

Rules the owner enforces

So far every add put its object on the list, no questions asked. But the object that owns the list can also have rules about what goes on it. A parking garage has a fixed number of spots, and the same car can't be parked in it twice:

Main.java
public class Main {
    public static void main(String[] args) {
        ParkingGarage garage = new ParkingGarage(2);
        System.out.println(garage.park(new Car("ABC-123")));
        System.out.println(garage.park(new Car("ABC-123")));
        System.out.println(garage.park(new Car("XYZ-789")));
        System.out.println(garage.park(new Car("JKL-456")));
        garage.leave("ABC-123");
        System.out.println(garage.park(new Car("JKL-456")));
        System.out.println(garage);
    }
}
ParkingGarage.java
import java.util.ArrayList;

public class ParkingGarage {
    private int spots;
    private ArrayList<Car> cars;

    public ParkingGarage(int spots) {
        this.spots = spots;
        this.cars = new ArrayList<>();
    }

    public boolean park(Car car) {
        if (this.cars.size() >= this.spots) {
            return false;
        }
        if (this.isParked(car.getPlate())) {
            return false;
        }
        this.cars.add(car);
        return true;
    }

    public boolean isParked(String plate) {
        for (Car car : this.cars) {
            if (car.getPlate().equals(plate)) {
                return true;
            }
        }
        return false;
    }

    public void leave(String plate) {
        for (int i = this.cars.size() - 1; i >= 0; i--) {
            if (this.cars.get(i).getPlate().equals(plate)) {
                this.cars.remove(i);
            }
        }
    }

    public String toString() {
        return this.cars.size() + "/" + this.spots + " spots taken: " + this.cars;
    }
}
Car.java
public class Car {
    private String plate;

    public Car(String plate) {
        this.plate = plate;
    }

    public String getPlate() {
        return this.plate;
    }

    public String toString() {
        return this.plate;
    }
}
Output
true
false
true
false
true
2/2 spots taken: [XYZ-789, JKL-456]
  • park checks its rules first, and adds the car only when all of them hold: there's a free spot, and no car with the same plate is parked. Each rule that fails returns false right away.
  • The boolean it returns tells the caller whether the car got in. main prints it here; a real program could print Garage full instead.
  • park uses another method of the same object, this.isParked(...). Small methods like this one can be useful to the caller too: garage.isParked("ABC-123").
  • After leave, there's a free spot again, and the car that was turned away gets in.

The rules always hold because the list is private. The only way onto the list is through park, and park checks every car. No other part of the program can put a car in past the rules, however it's written.

Don't hand out the list

Suppose ParkingGarage had a getter for its list:

public ArrayList<Car> getCars() {
    return this.cars;
}

It returns a reference to the garage's own list, not a copy (module 22). With it, garage.getCars().add(new Car("NEW-001")); puts a car straight on the list, past every rule, even into a full garage. So keep the list to the class, and give the class methods for what the rest of the program needs: park, leave, isParked, a toString.

The module's tools

Tool Example
A list as an instance variable private ArrayList<Book> books;
Made in the constructor this.books = new ArrayList<>();
A loop over the object's list for (Book book : this.books)
A toString built in a loop text = text + "\n" + book;
Removing while going through an index loop that goes backwards
A total from the objects total = total + book.getPages();
A search that may find nothing returns the object, or null
A rule checked before adding if (this.cars.size() >= this.spots)

Your task

Challenge 1 of 3

A day plan holds meetings, and two meetings can't be at the same time. A meeting has a title, and a start and an end hour: new Meeting("Review", 10, 12) is from 10 to 12. Meeting.java is ready, with the getters getStart() and getEnd(). In DayPlan.java, write the method add(Meeting meeting). It adds the meeting only when it doesn't overlap any meeting already on the plan, and returns true when the meeting was added, false when it wasn't.

Two meetings overlap when each one starts before the other one ends. A meeting from 9 to 10 and one from 10 to 12 don't overlap: the first ends just as the second starts. The check runs:

DayPlan plan = new DayPlan();
System.out.println(plan.add(new Meeting("Standup", 9, 10)));
System.out.println(plan.add(new Meeting("Review", 10, 12)));
System.out.println(plan.add(new Meeting("Lunch talk", 11, 13)));
System.out.println(plan.add(new Meeting("Call", 8, 9)));
System.out.println(plan);

and expects:

true
true
false
true
Booked: [Standup (9 to 10), Review (10 to 12), Call (8 to 9)]

Challenge 2

What does this program print? The dinner table lets a guest sit only when there's a free chair, but it also has a getter that returns its list.

Challenge 3

A five-a-side team keeps a roster of its players, and each player has a shirt number. Player.java is ready, with getName() and getNumber(), and a toString like #7 Ada. Roster.java has the team's name, the most players it may have, and the list. Write three methods in it:

  • add(Player player) adds the player and returns true, except when the roster is already full, or when a player on it already has the same shirt number. Then it adds nothing and returns false.
  • remove(int number) removes the player with that shirt number and returns true, or returns false when there's no such player.
  • toString() gives the team's name and how many players it has of the most it may have, like Otters: 2/3 players, and then each player on a line of its own.

The check runs:

Roster roster = new Roster("Otters", 3);
System.out.println(roster.add(new Player("Ada", 7)));
System.out.println(roster.add(new Player("Ben", 7)));
System.out.println(roster.add(new Player("Ben", 9)));
System.out.println(roster.add(new Player("Cleo", 4)));
System.out.println(roster.add(new Player("Dan", 11)));
System.out.println(roster.remove(9));
System.out.println(roster.remove(5));
System.out.println(roster);

and expects:

true
false
true
true
false
true
false
Otters: 2/3 players
#7 Ada
#4 Cleo