This programming assignment is the complement of the Design Document 2 assignment. The general task was already explained; this assignment description provides additional details and tips for the programming aspects of the redesign.
You must identify those classes with low cohesion and then split these
classes into separate classes exhibiting high cohesion. Since each of
these new classes will introduce a separate type, you may need to "root"
them at a single type (as defined by an interface
) to
satisfy Java's type checking rules. You will
not introduce any additional classes beyond those used to improve cohesion
(e.g., you will not use inheritance in this pair of assignments). This
refactoring is quite likely to increase the amount of code through the
duplication of some methods; this is expected and ok at this time.
Based on the original source code, there are likely two categories of
classes with low cohesion. The first category consists of those classes
that depend on ActionKind
or EntityKind
. The
second category depends on your final distribution of the methods in
the original Functions
class.
Kind: The original source code uses ActionKind
and
EntityKind
to allow each Action
instance
and each Entity
instance to play one of potentially many
roles (this mimics a tagged union). You are to eliminate these
*Kind
classes (enums) (the programmatic implications
of doing so are discussed in
Programming Assignment 2)
by splitting Action
and Entity
into
multiple new classes.
Other: Review all of the classes with an focus on cohesion. Does a class contain data that is not used by all instances of the class (i.e., each "kind" uses only subsets of the data)? Does a class contain methods that do not support the primary role of instances of the class (e.g., static methods that are used to create instances or parse files, but that are not actually part of the functionality provided by the instances)? For example, this is the time to make sure that the parse* methods for example find a better home.
As before, you are encouraged to develop both the UML design document and the code refactoring at the same time. You are further encouraged to implement the refactoring incrementally so that your refactored program executes properly at each step. You will submit the design document before the final refactoring submission to allow for feedback on your design that can then be incorporated into your refactoring.
Your refactoring should mirror the work done for your design document (UML diagram) augmented with feedback from your instructor.
Your refactoring must not add or remove any program functionality. The resulting program must work as before.
You can use the compiler (on the command-line or in the IDE) to help you with your refactoring. In particular, as you introduce interfaces, the compiler will report attempts to use methods not supported by the specified type. The existence of such errors may indicate missing methods for an interface or, more likely, attempts to treat a group of objects more generally than should be supported (i.e., not all of them implement the desired operation).
As part of your refactoring, you will be eliminating the *Kind
classes. This is desired to allow each new class to directly implement a
single role, but has the unfortunate side-effect of eliminating a simple
check of an object's "kind". This check is used, for instance, when
searching for the nearest Ore
to a miner.
Consider the following tips.
For a class that is being split into multiple class, change the original class into an interface declaring no methods. Compile the program to determine all uses of this interface (the method invocations will trigger compiler errors). Now determine which of these methods must be supported by all instances of this interface and which should be supported via additional interfaces.
You can copy the original class to, and change all references to,
NameTmp
and declare it to implement the new
interface so that most of the code will continue to compile.
For those methods that are not logically part of the primary interface defined in the prior step, introduce new interfaces and change the necessary variable declarations to use the new types.
A check for the "kind" of a referenced object can, for now
(though we will address this later), be replaced by a use of
instanceof
. Use this sparingly; certainly
instanceof
is not needed to check the type of
this
.
In the case that a *Kind
value was passed as a parameter
to another method (and then compared within), you can do the following.
Change the parameter type from the specific *Kind
to
Class
(this is a type where each instance represents
properties of a specific Java class).
Instead of passing a
*Kind
value, use .class
to get the object
associated with the desired Java class (e.g., String.class
gives the Class
object describing the String
class).
Change the comparison to use the isInstance()
method on
the Class
object, passing to this method the object
to be checked.
Your submission must include all source files (even those that were unchanged). Your grader should be able to build your project based on the files submitted. (You do not need to submit the image files, the image list, or the world save file.) An explicit list of files is not given because you are creating new files for this assignment, so verify that you have submitted everything properly.