Lab 04: Mini Problems
Learning Objectives
Students should
- be able to create immutable class.
- be able to create factory method.
- be able to work with generics.
Initializing
To get the files, run the following command from your PE node.
We recommend creating a new directory called mini
to store all your lab mini problems.
1 |
|
The files will only be available on Wednesday, 18 September 2024.
New Lab Problem
This problem is a new problem and no longer an extension of Lab 03.
Mini Problem 1
In this problem, we are going to create an immutable class. An immutable object refers to an object whose state cannot be modified after it is created (Wikipedia). You will learn more about immutability during lecture, but to motivate you for the time being, immutability makes it easy to reason about our code. Less changes == less bugs!
Point.java | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Task 1: Immutable Point
Recap the Point
class that we have above.
It is possible to mutate the variables by invoking the moveTo
method.
Mutable Point | |
---|---|
1 2 3 4 5 |
|
Make the class Point
immutable by making the following changes:
- Modify
void moveTo(int, int)
to return a newPoint
instead of mutating the current point. - If you are moving the point to the same coordinate as the current coordinate, return the current instance.
Your code should pass the following check.
Immutable Point | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Task 2: Factory Method
Now that we have an immutable point, we may find it weird that p
and p2
above are not identical (i.e., p == p2
returns false
) even when they are the same coordinates.
On the other hand, p2
and p3
are identical (i.e., p2 == p3
returns true
).
We want to do something similar but only for a special point called origin at (0, 0).
We will do this by implementing a factory method. A factory method is a static method that can be invoked to create an instance instead of exposing the constructor directly. This has several advantages that we will explore here.
Make the following changes to the Point
class to implement factory method with several advantages.
-
Make
Point
class behave in the following way:Factory v1 1 2 3 4 5 6 7 8 9
jshell> new Point(1, 1) | Error: | Point(int,int) has private access in Point | new Point(1, 1) | ^-------------^ jshell> Point p = Point.of(1, 1) p ==> (1,1) jshell> p.moveTo(2, 2) $.. ==> (2,2)
-
Modify
Point
class such that it returns the same instance if we are creating the origin point (i.e., point at (0, 0)). This is only possible because of the use of factory method. Ensure that you pass the following test.1 2 3 4 5 6 7 8 9 10 11 12
jshell> Point p1 = Point.of(0, 0) p1 ==> (0,0) jshell> Point p2 = Point.of(0, 0) p2 ==> (0,0) jshell> p1 == p2 $.. ==> true jshell> p1 = Point.of(1, 1) p1 ==> (1,1) jshell> p2 = Point.of(1, 1) p2 ==> (1,1) jshell> p1 == p2 $.. ==> false
-
Finally, we want our point to have only non-negative coordinates. If any of the inputs are negative, return
null
. Again, this is only possible with factory methods.1 2 3 4 5 6 7 8
jshell> Point p = Point.of(-1, 0) p ==> null jshell> Point p = Point.of(0, -2) p ==> null jshell> Point p = Point.of(3, -2) p ==> null jshell> Point p = Point.of(1, 3) p ==> (1,3)
Mini Problem 2
In this problem, we are going to implement generic class. In particular, we will expand on the implementation of generic pair.
Pair.java | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Task 1: Comparing Pair
We say that two pairs p1
and p2
are equal if both of the followings are true:
p1.first
is equal top2.first
according to theirequals
method.p1.second
is equal top2.second
according to theirequals
method.
However, you will notice that in some cases, you may get run-time errors. Try to figure out why and make sure that you pass the following test case by overriding the boolean equals(Object)
method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 |
|
Task 2: Swapping Elements
Since a pair has two fields first
and second
, we may be able to swap with another pair.
The swap is done in the following way when p1.swap(p2)
is invoked:
- We assign
p2.first
intop1.first
. - We assign
p1.second
intop2.second
.
We need to make sure that the method is the most flexible with the minimum number of type parameter it can be.
For that, we assume that we have the following three classes with the following subtyping relationship: C
<: B
<: A
.
1 2 3 |
|
We need to at least pass the following test.
1 2 3 4 5 6 7 8 9 10 11 |
|