| Class Dependency Diagram An oval/box represents a class. There is an arrow from class B to class A if
ACTIVITY |
We know we are always trying to avoid duplication of code. We know we are always trying to maximize separation of interface from implementation. Another maxim - and you may have heard this from a prof before - is this: if you have two tasks to perform, keep them separate, don't intermingle the two tasks in one piece of code. This a lower-tier maxim, because it's really more of a rule of thumb. Unlike the other two, it's OK to violate if the situation calls for it. But unless there's a darn good reason, you should follow it too.
So if you look at the actual code from the activity, you will
notice that there are some methods in
class SectionBank that are pretty similar:
public void printAll() {
for(Node p = first; p != null; p = p.next)
System.out.println(p.data);
} |
public void printMatchCourse(String course) {
for(Node p = first; p != null; p = p.next)
if (course.equals(p.data.getCourse()))
System.out.println(p.data);
} |
public Section find(String course, String number) {
Node p = first;
while (p != null
&& !(course.equals(p.data.getCourse())
&& number.equals(p.data.getNumber())))
p = p.next;
return p != null ? p.data : null;
} |
printAll
and printMatchCourse are clearly pretty
similar. A bit less clearly, printMatchCourse
and find are similar as well.
Can we get rid of some of this duplication?
printMatchCourse
and find both mix the tasks of iterating
through the collection of sections and checking whether
each sections "matches" some kind of criterion.
Can we separate the code that determines whether we have a
"match" from the code that iterates through the collection
of sections?
With these three mini-classes in place, we can replace the three function printAll, printMatchCourse, and find with two methods ... and simpler methods at that!
public void print(Matcher m) {
for(Node p = first; p != null; p = p.next)
if (m.match(p.data))
System.out.println(p.data);
} |
public Section find(Matcher m) {
Node p = first;
while (p != null && !m.match(p.data))
p = p.next;
return p != null ? p.data : null;
} |
Finally, we have to replace the calls in Proj01.main() of printAll, printMatchCourse and the old find method with our new methods:
sched.printAll() -becomes- sched.print(new Matcher())
bank.printMatchCourse(sc.next()) -becomes- bank.print(new MatchCourse(sc.next()))
bank.find(sc.next(),sc.next()) -becomes- bank.find(new MatchSection(sc.next(),sc.next()))
You can check out the full program
else if (comm.equals("fit"))
bank.print(MatchFit.make(sc.next(),sched));
So let's see how this magical matcher works (and see how the
class dependency diagram changes):
|
|
Notice how Proj01 has dependencies on Matcher and it subclasses, because Proj01 is where we choose which particular kind of Matcher we need, while SectionBank only depends on the base class, Matcher. That's important. From the perspective of the rest of the program, i.e. everything but Proj01, there are only Matchers out there, and which particular kind of Matcher is irrelevant. In fact, we may decide to collapse all the Matcher classes into one Node to clarify this: