4-Union of Classes and Methods
4-Union of Classes and Methods
Methods
1
Introduction
• Our railroad example distinguishes between two kinds
of trains with a boolean field.
• If the field is true, the instance represents a local train;
otherwise, it is an express train.
• While a boolean field may work for a simple distinction
like that, it really isn’t a good way to think about distinct
kinds of trains.
• It also doesn’t scale to large problems, which offer a
wide variety of trains with many distinct attributes,
e.g., city, local, regional, long distance, long distance
express trains, and so on.
• In this section, we show how to use classes to represent
distinct yet related kinds of information.
2
The Drawing Program
• Develop a drawing program that deals with at least three
kinds of shapes: dots, squares, and circles.
The shapes are located on a Cartesian grid whose origin
is in the northwest.
– A dot is located in the grid and is drawn as a small disk of
a fixed size (3 pixels).
– A square's location is specified via its north-west corner in
the grid and its size.
– A circle's essential properties are its center point and its
radius.
3
Class diagram Express the relationship
IShape between these classes,
An IShape is so that IShape as types of data
one of a Dot, a
Square, a Circle
Dot Square Circle
- CartPt location - CartPt nwCorner - CartPt center
- int size - int radius
CartPt
- int x
- int y
6
Test constructors
public class ShapeTest extends TestCase {
public void testConstructor() {
//test for class CartPt
CartPt p1 = new CartPt(4, 3);
CartPt p2 = new CartPt(5, 12);
7
Types vs Classes
• A class is a general description of a collection of objects that
provides a mechanism for constructing specific objects.
• An interface is a uniform “face” for several classes,
which you sometimes wish to deal with as if it were one.
• A type describes for what kind of objects a variable or a
parameter. In Java, a type is either the name of an interface,
a class, or a primitive type (int, double, boolean)
• When we write: IShape s;
– s has type IShape, which means that it is a placeholder for some
unknown (Dot, Square, Circle) shape.
• Similarly, when we introduce an example such as
IShape s = new Square(...)
– s has type IShape, even though it stands for an instance of Square.
8
Zoo example
• Develop a program that helps a zoo keeper take care of
the animals in the zoo. For now the zoo has lions, snakes,
and monkeys. Every animal has a name and weight. The
zoo keeper also needs to know how much meat the lion
eats per day, the length of each snake, and the favorite
food for each monkey
• Examples:
– The lion Leo weighs 300 pounds and eats 5 pounds of meat
every day;
– The snake Boa weighs 50 pounds and is 5 feet long;
– The monkey George weighs 150 poundds and loves
bananas.
– The monkey Mina weighs 120 pounds and loves to eat kiwi
9
Class diagram
IZooAnimal
10
Java definitions
public interface IZooAnimal {
}
11
Test constructor
public class AnimalTest extends TestCase {
public void testConstructor() {
// test for class Lion
IZooAnimal leo = new Lion("Leo", 300, 5);
IZooAnimal samba = new Lion("Samba", 200, 3);
IZooAnimal Cleopon = new Lion("Cleopon", 250, 5);
13
Recall the Drawing Program
IShape
CartPt
- int x
- int y
14
Requirements
1. Compute the area of a shape
2. Compute the distance of a shape to the origin
3. Determine whether some point is inside the shape
4. Compute the bounding box of a shape
• All of these methods clearly work with shapes in general
but may have to compute different results depending on
the concrete shape on which they are invoked
– For example, a Dot has no true area; a Square's area is
computed differently from a Circle's area
• In an object-oriented language, we can express this
requirement with the addition of a method signature to
the IShape interface
15
Add method for union of Shapes
IShape
??? nnn()
CartPt
- int x
- int y
??? kkk()
16
kkk() Method Template of CartPt
public class CartPt {
private int x;
private int y;
public CartPt(int x, int y) {
this.x = x;
this.y = y;
}
17
nnn() method template of Shape
public interface IShape {
public ??? nnn();
}
+ ??? area(???)
CartPt
- int x
- int y
19
Augmenting IShape
area() purpose and signature
public interface IShape {
// compute area of a shape
public double area();
}
class Dot implements IShape {
...
public double area() { ... }
}
class Square implements IShape {
...
public double area() { ... }
}
class Circle implements IShape {
...
public double area() { ... }
}
20
Examples
new Dot(new CartPt(4, 3)).area()
// should be 0.0
new Square(new CartPt(4, 3), 30).area()
// should be 900.0
new Circle(new CartPt(5, 5), 20).area()
// should be 1256.6...
21
Implement area() method
// inside of Dot
public double area() {
return 0.0;
}
// inside of Circle
public double area() {
return Math.PI * this.radius * this.radius;
}
// inside of Square
public double area() {
return this.size * this.size;
}
22
Unit Testing
public class ShapeTest extends TestCase {
public void testArea() {
assertEquals(new Dot(new CartPt(4, 3))
.area(), 0.0, 0.001);
assertEquals(new Square(new CartPt(4, 3), 30)
.area(), 900, 0.001);
assertEquals(new Circle(new CartPt(5, 5), 20)
.area(), 1256.637, 0.001);
Polymorphism
24
2. Computing the distance of a
shape to the origin
What is the distance between a shape and the
origin?
0 X
25
Add method to class diagram
IShape
+ double area()
+ ??? distanceToO(???)
CartPt
- int x
- int y
26
+ double distanceToO()
distanceToO() purpose and
signature
public interface IShape {
// compute area of AShape
public double area();
27
Implement distanceToO()
// inside of Dot
public double distanceToO() {
return this.location.distanceToO();
}
// inside of Square
public double distanceToO() {
return this.nwCorner.distanceToO();
}
// inside of Circle
public double distanceToO() {
return this.center.distanceToO();
}
28
distanceToO method in CartPt
public class CartPt {
private int x;
private int y;
29
Unit Test
public class ShapeTest extends TestCase {
...
30
3. Determining whether some point
is inside the shape
A given point is inside a DOT when its distance to
this DOT is 0.
a given point is inside a CIRCLE if its distance to the
center of the CIRCLE is less than or equal the
radius.
A given point is inside a SQUARE when it is
between two pairs of lines.
31
Add method
<<interface>>
IShape
to class +area()
+double distanceToO()
+??? contains(???)
diagram
Dot Square Circle
-CartPt location -CartPt nwCorner -CartPt center
-int size -int radius
+area()
+double distanceToO() +area() +area()
+??? contains(???) +double distanceToO() +double distanceToO()
+??? contains(???) +??? contains(???)
CartPt
-int x
-int y
+double distanceToO()
+double distanceTo(CartPt that) 32
contains() purpose and
signature
public interface IShape {
// compute area of AShape
public double area();
33
Examples
• new Dot(new CartPt(100, 200))
.contains(new CartPt(100, 200)) // should be true
• new Dot(new CartPt(100, 200))
.contains(new CartPt(80, 220)) // should be false
• new Square(new CartPt(100, 200), 40)
.contains(new CartPt(120, 220)) // should be true
• new Square(new CartPt(100, 200), 40)
.contains(new CartPt(80, 220)) // should be false
• new Circle(new CartPt(0, 0), 20)
.contains(new CartPt(4, 3)) // should be true
• new Circle(new CartPt(0, 0), 10)
.contains(new CartPt(12, 5)) // should be false
34
Domain Knowledge
• How to determine whether some point is inside the
shape is a kind of knowledge called DOMAIN
KNOWLEDGE
• To comprehend the domain knowledge, we
sometimes look up in a book and in other situations
we gather from experts
35
Implement contains()
// inside of Dot
public boolean contains(CartPt point) {
return this.location.distanceTo(point) == 0.0;
}
// inside of Circle
public boolean contains(CartPt point) {
return this.center.distanceTo(point) <= this.radius;
}
36
distanceTo() in CartPt
public class CartPt {
private int x;
private int y;
public CartPt(int x, int y) {
this.x = x;
this.y = y;
}
public double distanceToO() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
nwCorner.y
p.y
size
nwCorner.y + size
38
// inside of Square
public boolean contains(CartPt point) {
int nwx = this.nwCorner.getX();
int nwy = this.nwCorner.getY();
int px = point.getX();
int py = point.getX();
// return (px >= nwx && px <= nwx + this.size)
// && (py >= nwy && py <= nwy + this.size);
return this.between(px, nwx, nwx + this.size)
&& this.between(py, nwy, nwy + this.size);
}
//-----------------------------------------------------------
private boolean between(int value, int low, int high) {
return (low <= value) && (value <= high);
}
// inside of CartPt
public class CartPt {
private int x;
private int y;
public int getX() { return this.x; }
public int getY() { return this.y; }
} 39
Unit test
public class ShapeTest extends TestCase {
public void testContain() {
assertTrue(new Dot(new CartPt(100, 200))
.contains(new CartPt(100, 200)));
assertFalse(new Dot(new CartPt(100, 200))
.contains(new CartPt(80, 220)));
diagram +area()
+double distanceToO()
+boolean contains(CartPt point)
CartPt
-int x
-int y
+double distanceToO()
+double distanceTo(CartPt that)
41
4. Computing the bounding box
of a shape
• What is a Bounding Box?
A bounding box is the smallest square that completely surrounds the
given shape
• The bounding box for a Square is the given square itself.
• For a Circle, the bounding box is also a square,
– its width and height are 2 * radius and
– its northwest corner is one radius removed from the center of the
circle in both directions.
• The bounding box for a Dot is a square with no extent.
Mathematicians call this idea a special case
42
Add method <<interface>>
IShape
to class +area()
+double distanceToO()
+boolean contains(CartPt point)
diagram
+??? boundingBox(???)
CartPt
-int x
-int y
+double distanceToO() 43
+double distanceTo(CartPt that)
boundingBox
purpose and signature
public interface IShape {
// compute area of AShape
public double area();
44
Examples
new Dot(new CartPt(5, 5)).boundingBox()
// should be
new Square(new CartPt(5, 5), 0)
45
Implement boundingBox()
method
inside of Dot
public Square boundingBox() {
return new Square(this.location, 0);
}
inside of Square
public Square boundingBox() {
return new Square(this.nwCorner, this.size);
}
46
boundingBox method in Circle
// Not delegation
public Square boundingBox() {
return new Square(new CartPt(this.center.getX()-this.radius,
this.center.getY()-this.radius), this.radius * 2);
}
inside of CartPt
// translate this point to dX, dY distance
public CartPt translate(int dX, int dY) {
return new CartPt(this.x + dX, this.y + dY);
} 47
Unit test
public class ShapeTest extends TestCase {
...
48
equals method
inside of Square class
public boolean equals(Object obj) {
if (null==obj || !(obj instanceof Square))
return false;
else {
Square that = (Square) obj;
return (this.nwCorner.equals(that.nwCorner)
&& this.size == that.size);
}
}
Class +area()
+double distanceToO()
Diagram
+boolean contains(CartPt point)
+Square boundingBox()
CartPt
-int x
-int y
+double distanceToO()
+double distanceTo(CartPt that) 50
Abstract with Class
Common Data
51
Similarities in Classes
• Similarities among classes are common in unions.
• Several variants often contain identical field
definitions. Beyond fields, variants also sometimes
share identical or similar method definitions.
• Our first union is a representation of simple
geometric shapes. All three classes implement
IShape. Each contains a CartPt typed field that
specifies where the shape is located.
public class Dot public class Square public class Circle
implements IShape { implements IShape { implements IShape {
private CartPt location; private CartPt nwCorner; private CartPt center;
... ... ...
} } }
52
Common Fields, Superclasses
• In OOP, classes cannot only inherit from interfaces,
they can also inherit from other classes.
• This suggests the introduction of a common superclass
of Dot, Square, and Circle that represents the
commonalities of geometric shapes:
public class AShape implements IShape {
private CartPt location;
public AShape(CartPt location) {
this.location = location;
}
}
• Here the class represents two commonalities:
the CartPt field and the implements specification
53
Inheritance
• If we make Dot an extension of AShape, it inherits the
CartPt field and the obligation to implement IShape:
public class Dot public class Square public class Circle
extends AShape { extends AShape { extends AShape {
implements
contain
AShape CartPt
Dot Square Circle -CartPt location -int x
-int y
-CartPt location -CartPt nwCorner -CartPt center
-int size -int radius extends
public class AShape implements IShape { Can't to access private location field, so
private CartPt location; Call constructor of AShape superclass
public AShape(CartPt location) {
this.location = location;
} public class Square extends AShape {
} private int size;
public Square(CartPt location, int size) {
super(location);
this.size = size;
}
57
}
Contructor of Shape (format 1)
public class AShape implements IShape { Subclasses can access
protected CartPt location;
protected location
}
public class Dot extends AShape { common field inherits
public Dot(CartPt location) { form AShape
this.location = location;
}
} public class Square extends AShape {
private int size;
public Square(CartPt location, int size) {
this.location = location;
this.size = size;
}
} public class Circle extends AShape {
private int radius;
public Circle(CartPt location, int radius) {
this.location = location;
this.radius = radius;
}
}
58
Contructor of Shape (format 2)
public class AShape implements IShape { Subclasses call
private CartPt location;
constructor of
public AShape(CartPt location) {
this.location = location; AShape superclass
}
} public class Dot extends AShape {
public Dot(CartPt location) {
super(location);
}
} public class Square extends AShape {
private int size;
public Square(CartPt location, int size) {
super(location);
this.size = size;
}
} public class Circle extends AShape {
private int radius;
public Circle(CartPt location, int radius) {
super(location);
this.radius = radius;
}
59
}
Test constructors
public class ShapeTest extends TestCase {
public void testConstructor() {
//test for class CartPt
CartPt p1 = new CartPt(4, 3);
CartPt p2 = new CartPt(5, 12);
61
Methods of union of shape
• We designed several methods for plain shapes, including
area(), distanceToO(), contains(), and boundingBox()
<<interface>>
IShape
+area()
+double distanceToO()
+boolean contains(CartPt point)
+Square boundingBox()
} } }
Lifting distanceToO() method to
the abstract AShape class
• The distanceToO method was designed identically in all the
variants of a union with a common AShape superclass
• We can replace the abstract method in the AShape with the
method definition from the variants and delete the methods
from Dot, Square, and Circle. The lifted distanceToO
method in is now available in all three subclasses
public interface IShape { public abstract class AShape {
// to compute the distance of private CartPt location;
// this shape to the origin public double distanceToO() {
public double distanceToO(); return
... this.location.distanceToO();
} }
}
public class Dot public class Square public class Circle
extends AShape { extends AShape { extends AShape {
... ... ... 68
} } }
<<interface>>
IShape
Final +area()
+double distanceToO()
Union
class AShape
CartPt
-int x
70
protected attribute and method
• protected: the class itself and its subclass can
access this attribute / method.
72
The Fuel Consumption Problem
73
Problem Statement
• A school district needs to manage the fuel
consumption for its fleet of vehicles, which includes
school busses, cars, and trucks.
• Each vehicle has a fuel tank of some size (in
gallons).
• The district also knows the average mile-per-gallon
consumption of fuel per vehicle.
• The fuel consumption for cars and busses depends
on the number of passengers the vehicle carries;
the fuel consumption of a truck increases with its
load (in tons)
74
Class Diagram
• All vehicles has a fuel tank of
some size (in gallons) and
average mile-per-gallon IVehicle
consumption of fuel per
vehicle.
• We define an abstract class
AVehicle that contains the AVehicle
common fields of all vehicles: - double fuelTankVolume // in gallons
fuelTankVolumn and - double averageMilePerGallon
averageMilePerGallon.
75
Java data definitions
public interface IVehicle {
}
76
Java data definitions
public class Bus extends AVehicle {
private int nPassengers;
public Bus(double fuelTankVolume,
double averageMilePerGallon, int nPassengers ) {
super(fuelTankVolume, averageMilePerGallon);
this.nPassengers = nPassengers;
} public class Car extends AVehicle {
} private int nPassengers;
public Car(double fuelTankVolume,
double averageMilePerGallon, int nPassengers ) {
super(fuelTankVolume, averageMilePerGallon);
this.nPassengers = nPassengers;
}
} public class Truck extends AVehicle {
private double loadInTons;
public Bus(double fuelTankVolume,
double averageMilePerGallon, double loadInTons) {
super(fuelTankVolume, averageMilePerGallon);
this.loadInTons = loadInTons;
}
77
}
Examples
IVehicle c1 = new Car(15.0, 25.0, 1);
78
Requirement
• The manager needs to know how much it costs to
refuel a vehicle with empty fuel tank at the current
fuel prices so that the district can create estimates
for the gas budget
• Q: Improve the current class diagram and give more
examples
79
refuelCost() method signature
public interface IVehicle {
// Compute how much it costs to refuel this vehicle
// with empty fuel tank at the current fuel prices
public double refuelCost(double costPerGallon);
}
b1.refuelCost(2.00)
// should be 120.0
c1.refuelCost(2.00)
// should be 30.0
t1.refuelCost(2.00)
// should be 240.0
81
Implementation of refuelCost()
• Since three subclasses have the same implementation for
refuelCost(), we could move this method to the superclass.
This means refuelCost() now in the AVehicle class will not
be abstract any more
public abstract class AVehicle implements IVehicle {
private double fuelTankVolume; // in gallons
private double averageMilePerGallon;
protected AVehicle(double fuelTankVolume,
double averageMilePerGallon) {
this.fuelTankVolume = fuelTankVolume;
this.averageMilePerGallon = averageMilePerGallon;
}
public double refuelCost(double costPerGallon) {
return costPerGallon * this.fuelTankVolume;
}
}
82
Improved Class Diagram
IVehicle
AVehicle
- double fuelTankVolume // in gallons
- double averageMilePerGallon
83
One More Requirement
• The manager wants to compute the projected fuel
consumption for a specific trip so that the various
departments can get a proper projection for the cost
of the transportation services. For busses, the fuel
consumption increases by 1% with each passenger.
For a car, the fuel consumption increases by 10%
with each passenger. For truck, one ton of load
increases the fuel consumption by 5%
• Notice that the fuel consumption is measured in
miles per gallon
• Q: Improve the current class diagram and give more
examples
84
fuelConsumption() signature
public interface IVehicle {
public double refuelCost(double costPerGallon);
// compute the fuel consumption of this vehicle
public double fuelConsumption();
}
public abstract class AVehicle implements IVehicle {
private double fuelTankVolume; // in gallons
private double averageMilePerGallon;
protected AVehicle(double fuelTankVolume,
double averageMilePerGallon) {
this.fuelTankVolume = fuelTankVolume;
this.averageMilePerGallon = averageMilePerGallon;
}
public double refuelCost(double costPerGallon) {
return costPerGallon * this.fuelTankVolume;
}
public abstract double fuelConsumption();
}
85
More Examples
IVehicle b1 = new Bus(60.0, 10.0, 20);
IVehicle c1 = new Car(15.0, 25.0, 1);
IVehicle t1 = new Truck(120., 6.0, 0.5);
b1.fuelConsumption()
// should be 8
c1.fuelConsumption()
// should be 22.5
t1.fuelConsumption()
// should be 5.85
86
fuelConsumption() implement
• In this case, all three methods are distinct from each
other, and they must be defined for each specific
concrete class of vehicles.
// inside Bus
public double fuelConsumption() {
return this.averageMilePerGallon
* (1 – 0.01*this.nPassengers);
}
// inside Car
public double fuelConsumption() {
return this.averageMilePerGallon
* (1 – 0.1*this.nPassengers);
}
// inside Truck
public double fuelConsumption() {
return this.averageMilePerGallon
* (1 – 0.05*this.loadInTons);
} 87
Improved Class Diagram
IVehicle
AVehicle
- double fuelTankVolume // in gallons
- double averageMilePerGallon
Measured in
+ double refuelCost(double costPerGallon)
miles per gallon
+ double fuelConsumption()
89
howFar() in AVehicle
public interface IVehicle {
public double refuelCost(double costPerGallon);
public double fuelConsumption();
// compute how far this vehicle can go
public double howFar();
}
public abstract class AVehicle implements IVehicle {
private double fuelTankVolume; // in gallons
private double averageMilePerGallon;
protected Avehicle(double fuelTankVolume,
double averageMilePerGallon) {
this.fuelTankVolume = fuelTankVolume;
this.averageMilePerGallon = averageMilePerGallon;
}
public double refuelCost(double costPerGallon) {
return costPerGallon * this.fuelTankVolume;
}
public abstract double fuelConsumption();
public abstract double howFar();
} 90
howFar() implement
• Since three subclasses have the same
implementation for howFar(), we could move this
method to the parent class.
This means howFar() now in the AVehicle class
will not be abstract any more
91
Final Class Diagram
IVehicle
AVehicle
- double fuelTankVolume // in gallons
- double averageMilePerGallon
+ double refuelCost(double costPerGallon)
+ double fuelConsumption()
+ double howFar()
94
4.3 Extended exercises
• The administrators of metropolitan transportation
agencies manage fleets of vehicles.
Develop data definitions for a collection of such
vehicles. The collection should include at least
buses, limos, cars, and subways. Add at least two
attributes per class of vehicle.
95
Exercise 4.4
• Class diagram for the classes in the shape hierarchy
CartPt
AShape
- int x
- CartPt location - int y
99
Exercise 4.7
• Recall the class hierarchies concerning taxi vehicles
from exercise 4.3:
ATaxiVehicle
# int idNum
# int passengers
# int pricePerMile
Limo Van
Cab
- int minRental - boolean access
100
Exercise 4.7 (cont)
Add the following methods to the appropriate classes in the
hierarchy:
• fare, which computes the fare for a vehicle, based on the
number of miles traveled, and using the following
formulas for different vehicles:
– passengers in a cab just pay flat fee per mile
– passengers in a limo must pay at least the minimum rental fee,
otherwise they pay by the mile
– passengers in a van pay $1.00 extra for each passenger
• lowerPrice, which determines whether the fare for a
given number of miles is lower than some amount;
• cheaperThan, which determines whether the fare in one
vehicle is lower than the fare in another vehicle for the
same number of miles.
101
Exercise 4.8
• Develop a program that assists a bookstore manager in a
discount bookstore. The program should keep a record for
each book. The record must include its title, the author's
name, its price, and its publication year. In addition, the books
There are three kinds of books with different pricing policy.
The hardcover books are sold at 20% off. The sale books are
sold at 50% off. The paperbacks are sold at the list price.
Here are your tasks:
• Develop a class hierarchy for representing books in the
discount bookstore.
• Develop the following methods:
– salePrice, which computes the sale price of each book;
– cheaperThan, which determines whether a book is cheaper
than another book;
– sameAuthor, which determines whether a book was written by
some given author which wrote another book.
102