During the refactoring pass of the previous optional assignment (2a), you likely noticed
a fair amount of duplication (both in terms of instance variables and
methods) when breaking Entity
into multiple separate classes.
For this assignment, you will eliminate this duplication by refactoring
the duplication into new abstract
classes. The entity classes
will then inherit the variables and methods, as appropriate, to restore
the functionalty.
abstract
classes? Instances of these new classes
will not be meaningful in the context of the program. Declaring
the class abstract
prevents instantiation, but still
allows for inheritance.
With a focus on "entities" (all classes implementing the concept of an
Entity
from the original, provided implementation), examine
the set of classes to identify duplication. Refactor the duplicate
variables/methods into a hierarchy of abstract
classes. The
goal (and, to be both explicit and pedantic, the requirement for this
assignment) is to eliminate all such duplication. This may seem
excessive, but it is often illustrative to apply a principle to the extreme
to see if it continues to provide benefits and to get a sense for when it
might fall short.
Completion of this assignment will consist of
Inheritance.graphml
)
Such duplication is most obvious
for instance variables (for this project, you can ignore any duplication of
static
variables, like rand
), since you may be
able to identify duplication directly from the names and (matching or
closely related) types (though there are times when two classes use different
names for conceptually duplicate variables).
Identifying duplicate methods will require careful examination of the code within the potentially duplicate methods (the names and parameters must generally match to start). You will find that the initial set of methods to consider are those specified by the interfaces introduced in the previous assignment.
Your refactoring should not abuse inheritance with regard to methods.
In particular, assume you have identified method foo
as
common among three classes (A
, B
,
and C
), but only two of them (B
and C
)
define the method identically. You should not promote one implementation
of foo
(e.g., from B
and C
) to the
new parent class only to then redefine it in some subclasses (e.g., in
A
). Instead, define an abstract
class (named
Abby
for this example) with an abstract
method
foo
. A
can extend Abby
and define
its implementation of foo
. Another new abstract
class can also extend Abby
to define the single implementation
of foo
used by B
and C
(which then
extend this new class).
At no point should a class inherit instance variables or methods due to this refactoring that it did not already possess prior to the refactoring. If such happens, then your refactoring either lifted something too high in the class hierarchy or it needs an additional intermediate class.
As before, all data should remain private
. If a subclass
needs to access/change this data, then it can do so via accessor or mutator
methods. If such methods do not exist, then you can add them (as
protected
methods) to the abstract
class.
You are strongly encouraged to begin this refactoring by updating your UML document first (referencing the code, of course, for method implementations). Doing so allows you to leverage the graphical aspects of UML to immediately identify duplication and to quickly refactor by injecting intermediate classes. Experience with this project indicates that the majority of duplication can be identified and refactored quickly through this approach, which then gives you have a design guideline for the code modifications. (Focus on the most obvious duplications first.)
Your refactoring should mirror the work that you do for your design document (UML diagram). Your refactoring must not add or remove any program functionality. The resulting program must work as before.
Some of the various entity classes contain identical methods (of course they do, these duplicates were added in the previous assignment). But there are also some methods from the orginal given code that are less obvious duplicates. In addition, there are some methods that are not full duplicates, but that do contain significant amounts of code duplication (your IDE might even be able to help identify these if you use the code review tools).
Consider the following tips for refactoring the less obvious duplications. This should be done after refactoring (both in UML and in the code base) the more obvious duplications so that there is less code to consider.
For two methods that appear to be doing roughly the same thing, but that differ slightly in their implementation: examine the code to determine if the code can be rewritten to match. This does require careful consideration for what each method does (and does not) to avoid introducing bugs.
Some methods may have the same general structure (and match
identically in significant portions), but differ in some
segments. For such methods, the general structure and identical
portions can be refactored into a parent class. This parent class
will declare new protected abstract
method(s) that
each subclass then implements to define the unique behavior (as
done in the calculator lab).
Your submission must include
Inheritance.graphml