In Team.java, write a public class named Team.
For now just the basic class definition.
In Player.java, write a public class named
Player. It will represent one player on a team.
Give Player four private instance variables: a
String name, an int
number (their jersey number), an int
points (how many points they have scored so far), and a
Team team: the team they are on, or
null if they aren’t on one. Yes, an instance variable can
hold an object of a class you wrote yourself, exactly the way it can
hold a String.
Write a constructor that takes a String name and an
int number and initializes those two instance variables. A
new player hasn’t scored any points yet and isn’t on a team, which is
what the int and object instance variables will be if you
leave them alone: 0 and null.
Write getters for all four instance variables: getName,
getNumber, getPoints, and
getTeam. Note that getTeam returns a
Team.
Write a method, scored, that takes an int
number of points and adds it to the player’s total.
Write a toString method that returns a String
of the form "Player where
Alice is the name, 10 the number, and
12 the points.
Give Team three private instance variables: a
String name, a
List<Player> players holding the
players on the team, and a Player captain,
which is null until someone is made captain. Declare the
list as a List, the interface, not as an
ArrayList: the rest of the class only cares that it is
a list, and which kind is the constructor’s business. You will
need to import java.util.List; (and, for the constructor,
java.util.ArrayList) at the top of the file.
Write a constructor that takes a String name. Besides
storing the name it needs to create the empty list that will hold the
players, with new ArrayList<>(): the instance
variable is declared as a List, but a List is
only an interface, so the actual object has to be some concrete kind of
list, and ArrayList is the usual choice. A list instance
variable you never assign to is null, not an empty list,
and the first addPlayer will blow up.
Write getters for name and captain:
getName and getCaptain. Do not write
a getPlayers: handing out the list would let any other code
add and remove players behind the team’s back, which is exactly what we
are trying to prevent. The methods below are how the rest of the program
asks about the players.
Player gets exactly one setter, setTeam,
which takes a Team and stores it. This exists so
that Team can tell a player what team they are on; the
rest of the program should never call it directly but should go through
the Team methods below, which keep both sides consistent.
None of the other instance variables get setters: a player’s name and
number don’t change, and points change only through
scored.
Write a method, addPlayer, that takes a Player and
adds them to the team. If the player is already on this team (the
list’s own contains method can tell you) it does nothing.
Otherwise it has two jobs: put the player in the team’s list, and tell
the player that this is now their team, using the player’s
setTeam. Inside a method of Team, the team
itself is this.
(addPlayer doesn’t worry about whether the player is currently on
some other team; moving a player between teams is
transferTo’s job, below.)
Write a method, size, that takes no arguments and returns
the number of players on the team.
Write a method, onTeam, that takes no arguments and
returns a boolean saying whether the player is on a team.
Write a method, removePlayer, that takes a Player
and removes them from the team. If the player isn’t on the team it does
nothing. Otherwise, like addPlayer, it has to fix up both sides:
take the player out of the list and set the player’s team to
null. And one more thing: if the player being removed was
the captain, the team no longer has a captain.
Write a method, makeCaptain, that takes a
Player and makes them the captain, but only if they are on
the team. If they aren’t, the captain is left as it was. (This is why
it isn’t called setCaptain: a setter stores whatever it is
given, and this method doesn’t.)
Write a method, totalPoints, that takes no arguments and
returns an int, the total of the points scored by all the
players on the team.
Write a method, topScorer, that takes no arguments and
returns the Player on the team with the most points. If
two players are tied, return the one that was added to the team first.
If the team has no players, return null.
Write a method, isTeammateOf, that takes another
Player and returns a boolean saying whether
the two players are on the same team. Two players with no team are not
teammates, and a player is not their own teammate.
Write a method, transferTo, that takes a
Team and moves the player to it: if the player is
currently on a team, they are removed from it, and then they are added
to the new team. Use the Team methods you already wrote
rather than touching the team instance variable yourself,
and both teams and the player will all agree about what happened. (This
is the one method whose test depends on other methods of yours:
transferTo is only as good as the addPlayer
and removePlayer it calls.)
Write a toString method for Team that returns a
String of the form
"Team:
the name, a comma, and then the list of players. The part in square
brackets is exactly what you get by sticking the list itself into the
string: an ArrayList’s own
toString puts its elements between [ and
], separated by ", ", and it describes each
element by calling its toString, which is the one
you wrote for Player. A team with no players prints as
"Team.
Each method’s own test above checks just that method, setting up the
team’s instance variables directly, so a broken addPlayer
can’t fail the size test. These last tests instead use
your methods the way a program would, in sequence, and check that they
agree with each other. This one builds a roster: after
addPlayer, the team’s size and
toString should change accordingly and the player’s
onTeam, getTeam, and
isTeammateOf should say so; after
removePlayer, all of that should be undone.
makeCaptain and getCaptain as players are
added and removed: a non-member can’t be made captain, a member can,
and removing the captain leaves the team without one.
scored against getPoints,
totalPoints, topScorer, and
toString: the team’s totals and top scorer should follow
the players’ points as they score, join, and leave.
Players moving between teams with transferTo: afterwards
the sizes of both teams, each player’s getTeam and
isTeammateOf, the old team’s getCaptain, and
both teams’ toString should all tell the same story.
In Point and Color you wrote one class at a
time. Real programs are made of many classes that refer to each other, so
this time you’ll write two: a Player and a Team.
A Player knows which Team they are on and
a Team keeps a list of its Players, which means
the two classes have to work together to keep their stories straight: when
a Team adds a Player, that player’s idea of
which team they’re on has to change too.
There are two files, Team.java and Player.java,
one per class. (In Java each public class goes in a file of its own,
named after the class.) The two files are compiled together so code in
either one can use the other class. The tests are labeled with which
class they are about. The suggested order is roughly top to bottom, but
the two classes depend on each other, so you will go back and forth.