How well are you prepared for the final?
This exercise should help you find out.
Piazza discussions encouraged!
// Chooser - a class badly in need of generics!
// Bloch 3rd edition, Chapter 5, Item 28: Prefer lists to arrays
public class Chooser<E> {
// Overview: A Chooser is a non-empty bag of "E"s
// rep-invariant?
// would a map be a better representation?
private final List<E> choiceList;
public Chooser (List<E> choiceList) {
this.choiceList = choiceList;
}
// return a random E from this
public E choose() {
Random rnd = ThreadLocalRandom.current();
return choiceList.get(rnd.nextInt(choiceList.size()));
}
// A mutator to add a choice
public void addChoice( E choice) {...}
// standard recipe or no?
@Override public boolean equals (Object obj) {...}
// standard recipe or no?
@Override public int hashCode () {...}
// what is appropriate here?
@Override public String toString () {...}
}
- The (client-visible) overview constrains the implementation.
How does it do that,
and how should the rep-invariant capture that constraint?
- The constructor's implementation fails Liskov's correctness test.
Explain, then fix it.
- Write a reasonable contract for the constructor.
- Bloch wouldn't like the method header for the constructor.
Why not? Fix it.
- Besides the correctness problem, the constructor's implementation has another
problem that Bloch would object to. What is it? Fix it.
- Given the overview, what should be the output
of a reasonable
toString()
method? Show some examples.
- Is Bloch's standard recipe for
equals()
appropriate here?
If not, give a test case that shows the problem.
Do the same for hashCode()
.
- Specify and implement
addChoice()
.
- Suppose we want the
Chooser
class to be immutable.
What has to change?
- Suppose we decide to disallow
null
values in the Chooser
.
Is this client visible? Should this change the rep-invariant? What changes?