CPE
102
Winter
2008
Program
3
Due
Date
You must turn in a functionally
correct program to receive any credit.
The grade you receive will be based on when you turn it in minus any
deductions for the quality of your implementation and/or multiple submissions. There is no deduction for the first
submission and a 5%
deduction for each additional submission, if any. Programs will be checked for correctness once a day and you will
be notified by email if your submission is not functionally correct. Programs will be graded after the last due
date and the results will be emailed to you within a few days of that date.
100% (minus any deductions) by 9:00pm Monday, 1/28/08
90% (minus any deductions) by 9:00pm Tuesday, 1/29/08
80% (minus any deductions) by 9:00pm Wednesday, 1/30/08
70% (minus any deductions) by 9:00pm Thursday, 1/31/08
You must also turn in a UML Diagram for
the program in lecture on Monday 1/28
– no late diagrams accepted. The diagram is worth 10% of your program
grade and may be hand-drawn.
Errata:
None
Objectives
- To become familiar with Java
inheritance.
- To compare and contrast the
features inheritance and interfaces.
- To become familiar with
abstract classes.
- To learn the difference
between deep and shallow copies of objects.
- To learn how to properly
overriding the equals() method of the Object class.
- More exposure to the concept
of polymorphism.
Resources
- Java Standard API
- P3TestDriver.java to be published Monday 1/28.
- P3UnitTests.zip
- UML Overview
Orientation
- You will be modifying your Program
2 implementation to take advantage of your new-found skills with Java inheritance.
Now that you know about inheritance you realize there is a better way to
implement your solution to Program 2. Much of the code and instance
variables defined in the various classes that implement the Shape interface
turned out to be identical. You now realize that using inheritance would
allow you to avoid duplicating this code and data. In addition to this
redesign, and the code modifications it requires, you will be adding some
additional features. You will be implementing the Comparable interface so
that you can order shapes bases on their type and area and implementing a new
shape, Square, that will require very little new code due to inheritance and
its close geometric relationship with rectangles.
- In addition to taking advantage of
inheritance you also realized that your implementation for Program 2 was
vulnerable to having the instance variables of your class being modified by
code outside the class. This is because
you did not make deep copies of all mutable objects being passed in and/or out
of the classes via constructors and methods.
You will fix this vulnerability in Program 3.
- JUnit tests will be provided in P3UnitTests.zip.
A stubbed out version of RectangleTest.java is given. You can
replace this with your completed version from Program 2 but then be
sure to modify your existing RectangleTest.java JUnit code to
test for deep copies. SquareTest.java
is given as an incomplete stub. You will need to write JUnit
tests for the methods you write in SquareTest.java. Use the JUnit
tests for other shapes as references to write the test code.
Lastly, a new method is introduced in the AbstractShape class
which is called compareTo(). You will need to write a JUnit test
to test this method in the WorkspaceTest.java file. As a recap:
- Modify RectangleTest.java to test for deep copies
- Write JUnit tests for SquareTest.java
- Write the testCompareTo() method in WorkspaceTest.java
Specification
- You MUST implement the
classes and methods exactly as described. Where exact specifications
are not given you are expected to meet the spirit of the specification as
given. Ask you instructor for clarifications as necessary, the
earlier the better!
- Using the javadoc-style,
document all public methods in the WorkSpace class and
all public methods of the Square class including
those documented in the Shape interface but having different behavior from
that specified in the Shape interfaces.
- All classes must make deep copies of
any mutable (changeable) objects being used as instance variables coming
in or going out of the class. This
includes the constructors and/or methods of the classes. This means no other code will ever have
a reference to any instance variables of any of your classes.
- Implement a Java abstract
class called AbstractShape
as follows:
- Implements the Shape
interface.
- Has a single constructor
that accepts one parameter for each of the instance variables of the
class (see 4.d below).
- Implements only the methods
in Shape that have common behavior in all of the subclasses,
Circle, Rectangle, Triangle, ConvexPolygon, and Square (a new shape to be
implemented in this program).
- Defines the instance
variables that are common to all of the subclasses.
- Implements the Comparable
interface so that its compareTo method indicates
that object-A is less than object-B when A’s class name is less that B’s
or, if A and B are the same class, when A’s area is less than B’s area;
indicates A and B are equal when they are the same class and have the
same area (+/- 0.0001); and indicates A is greater than B when A’s class
name is greater than B’s or, if A and B are the same class, when A’s area
is greater than B’s area. You can use the following code to obtain
any object’s name:
String className =
yourObjectRef.getClass().getName();
- Notice that the name is a
String and there may be methods of the String class that will help you
compare the class names (see the Java Standard API).
- Override the equals() method
of the Object class so that it returns true if the two objects being
compared are the same class, not null, and have
equal values for all instance variables.
- Modify Circle so that it
extends AbstractShape rather than implements the Shape
interface.
- Implement only the methods
that must be implemented in the Circle class and inherits the others from
AbstractShape.
- Implement only the instance
variables that must be implemented in the Circle class and inherits the
others from AbstractShape.
- Override the equals() method
of the Object class so that it returns true when the objects being
compared are both the same type, are not equal to null, and all of their
instance variables, defined here and in any super classes, have equal
values for all instance variables.
- Modify Rectangle so that it
extends AbstractShape rather than implements the Shape
interface.
- Implement only the methods
that must be implemented in the Rectangle class and inherits the others
from AbstractShape.
- Implement only the instance
variables that must be implemented in the Rectangle class and inherits
the others from AbstractShape.
- Override the equals() method
of the Object class so that it returns true when the objects being
compared are both the same type, are not equal to null, and all of their
instance variables, defined here and in any super classes, have equal
values for all instance variables.
- Modify your JUnit code to
test for deep copies.
- Modify Triangle so that it
extends ConvexPolygon rather than implements the Shape
interface.
- Implement only the methods
that must be implemented in the Triangle class and inherits the others
from ConvexPolygon.
- Implement only the instance
variables that must be implemented in the Triangle class and inherits the
others from ConvexPolygon.
- Override any methods
inherited from ConvexPolygon only as
necessary.
- Note:
When calling the super constructor of ConvexPolygon in Triangle's
constructor you will have to constuct an array of points in the super
call using array initialization syntax. That syntax is not
obvious, so here is an example for you to use:
super(new Point[] {a, b, c}, et cetera...);
This
assumes that Point references called a, b, and c have been passed as
parameters to the Triangle constructor - change the names as necessary
in your implementation.
- Modify ConvexPolygon so
that it extends AbstractShape rather than
implements the Shape interface.
- Implement only the methods that
must be implemented in the ConvexPolygon class and inherits the others
from AbstractShape.
- Implement only the instance
variables that must be implemented in the ConvexPolygon class and
inherits the others from AbstractShape.
- Override the equals() method
of the Object class so that it returns true when the objects being
compared are same type, are not equal to null, and all of their instance
variables, defined here and in any super classes, have equal values for
all instance variables.
- Implement a class called Square
so that it extends the Rectangle as follows:
- Square(double size,
java.awt.Point position, Color color, boolean filled) – Constructor.
- Since a square is,
geometrically speaking, a rectangle, the Square class should have no
explicit instance variables and will, instead, make use of its
super-class’s instance variables.
- Override any methods
inherited from Rectangle only as necessary.
- Implement unit tests in SquareTest.java to test the Square class.
- The WorkSpace methods
should have identical behavior to their Program 2 behavior. Some of its methods will require some
modification because of the use of inheritance. Because Square is a subclass of Rectangle you will need to
modify the code in the getRectangles method so that it does not return
Square objects too. The same is
true for getConvexPolygons since the Triangle class is now a subclass of
ConvexPolygon. While one could make
an argument that squares are rectangles and triangles are convex polygons
it is a useful exercise for you to learn how to be more class specific
when dealing with classes that make use of inheritance.
- Implement AbstractShape's testCompareTo() method in WorkspaceTest.java
Suggestions
- Be sure your Program 2 code
passes its test driver (provided last week) before beginning
Program 3. Ask you instructor for help if you are not sure how to
resolve any remaining issues. Remember – you may not
collaborate on programs.
- Create a NEW project
in your IDE for Program 3 and make separate physical copies of your
Program 2 files for it rather than modifying you Program 2 code
directly. You may want your original Program 2 source as a
reference. Different IDEs have unique subtleties for adding existing
source to a new project – make sure you understand the subtleties of your
chosen development environment. If
you are not sure about how you IDE works, ask a trusted friend, your
instructor, or experiment with unimportant code until you know what you
are doing.
- Develop incrementally – this
means implement AbstractShape and use it to extend one of your shapes and
test that code well before moving on to the other shapes. This way
you will avoid repeating the same mistakes in each shape.
- Implement the new shape,
Square, after you have successfully modified your existing shapes –
especially Rectangle.
- Keep
track of your hours worked as you go, so you don’t have to guess when you
hand in your assignment (see handin section below for information on
time.txt).
Testing
With the Provided Tests
- Your code must be 100% correct
to recieve credit. Correctness will be determined by running the acceptance
test P3TestDriver.java to be published Monday 1/28.
- In addition to the acceptance
test, sections 7 and 9 will be graded on the quality of JUnit tests they
create for this program, section 3 will not.
- Use the JUnit tests while
developing in a test-driven approach to ensure your code's correctness
before the acceptance test is released. Run them by opening the
AllTests.java file and executing it.
- Ask
your instructor for assistance if you are not able to run these tests on
your own.
Handing
in Your Source Electronically…
- Create a plain text file called
time.txt to log the amount of time spent on the assignment. The file will contain only three lines
with the following information on each line: name, project number, hours
spent.
Example time.txt file:
Sally Student
Program 1
7.5 hours
- Move the necessary file(s) to
your vogon account using your favorite FTP client program.
- Log on to vogon using your
favorite Shell client program.
- Change directory (cd-command)
to the directory containing the file(s) to hand in. Be sure you code compiles and runs
correctly on hornet before turning it in!
- Use the following handin command
being sure to replace the x with the correct maximum score you can
earn based on the due date, i.e., replace x with 100 if you are handing
in by Monday’s deadline, 90 for Tuesday, 80 for Wednesday, or 70 for
Thursday, for example Program3-100, Program3-90, et cetera.
12:01pm vogon ~$ handin graderkm Program3-x
Shape.java AbstractShape.java Circle.java Rectangle.java Triangle.java ConvexPolygon.java
Square.java WorkSpace.java RectangleTest.java SquareTest.java WorkspaceTest.java time.txt