5.3.5

## Lecture: Methods for unions

Design methods for unions of classes of data.
Practice using wish lists. Wish lists.

IShape.java

### Lecture outline

• Methods for unions of classes

• Reinforce the use of the Design Recipe

### 1Designing Methods for Unions of Classes

Here are our two classes that represent shapes - we defined them to implement the common interface IShape.

The class diagram below shows our ambitious program - of designing five methods for these classes.

 +---------------------------------+ | IShape                          | +---------------------------------+ +---------------------------------+ | double area()                   | | boolean distTo0()               | | IShape grow(int inc)            | | boolean biggerThan(IShape that) | | boolean contains(CartPt pt)     | +---------------------------------+ | / \ --- | ------------------------------- |                             | +---------------------------------+          | | Circle                          |          | +---------------------------------+          | +-| CartPt center                   |          | | | int radius                      |          | | | String color                    |          | | +---------------------------------+          | | | double area()                   |          | | | boolean distTo0()               |          | | | IShape grow(int inc)            |          | | | boolean biggerThan(IShape that) |          | | | boolean contains(CartPt pt)     |          | | +---------------------------------+          | |                                              | |                       +--------------------------------+ |                       | Square                         | |                       +--------------------------------+ |                     +-| CartPt nw                      | |                     | | int size                       | |                     | | String color                   | |                     | +--------------------------------+ |                     | | double area()                  | |                     | | boolean distTo0()              | |                     | | IShape grow(int inc)           | |                     | | boolean biggerThan(IShape that)| |                     | | boolean contains(CartPt pt)    | |                     | +--------------------------------+ |                     | +----+ +--------------+ | | v v +--------+ | CartPt | +--------+ | int x  | | int y  | +--------+

We want to design the following mtehods that would work for any shape - the two we have defined now, and any other shape class we may define in the future (for example a Square class.

•  // to compute the area of this shape public double area();
•  // to compute the distance form this shape to the origin public double distTo0();
•  // to increase the size of this shape by the given increment public IShape grow(int inc);
•  // is the area of this shape is bigger than the area of the given shape? public boolean biggerThan(IShape that);
•  // does this shape (including the boundary) contain the given point? public boolean contains(CartPt pt);

To compute the area of a shape in DrRacket the function purpose, contract and header would have been:

 ;; to compute the area of the given shape ;; area : Shape -> Number (define (area ashape) ...)

and the template would have been:

 ;; to compute the area of the given shape ;; area : Shape -> Number (define (area ashape) (cond [(circle? ashape) ...] [(square? ashape) ...]))

In Java the methods that deal with each type of object are defined within the class definition for that class of objects. So the area method that computes the area of a circle is defined in the Circle class and the area method that computes the area of a square is defined in the Square class.

A union of several classes in Java is represented by an interface type. We would like to assure that every class that implements our IShape interface does indeed define the method #area. The interface definition, that until now looked likejust an empty shell of a code, indeed can define method headers for some methods. That defines a contract between the interface and the classes that implement the interface. Every class that implements the interface is required to implement all methods that the interface specifies. In turn, if we use any object of the type specified by the interface, we are guaranteed that a method defined in the interface can be invoked by this object.

So, our code would look like this:

 // to represent a geometric shape interface IShape { // to compute the area of this shape public double area(); } // to represent a circle class Circle implements IShape { CartPt center; int radius; String color; Circle(CartPt center, int radius, String color) { this.center = center; this.radius = radius; this.color = color; } /* TEMPLATE FIELDS: ... this.center ...              -- CartPt ... this.radius ...              -- int ... this.color ...               -- String METHODS ... this.area() ...                  -- double */ // to compute the area of this shape public double area() { return Math.PI * this.radius * this.radius; } } // to represent a square class Square implements IShape { CartPt nw; int size; String color; Square(CartPt nw, int size, String color) { this.nw = nw; this.size = size; this.color = color; } /* TEMPLATE FIELDS: ... this.nw ...              -- CartPt ... this.size ...            -- int ... this.color ...           -- String METHODS: ... this.area() ...                  -- double */ // to compute the area of this shape public double area() { return this.size * this.size; } } class ExamplesShapes { ExamplesShapes() {} IShape c1 = new Circle(new CartPt(50, 50), 10, "red"); IShape s1 = new Square(new CartPt(50, 50), 30, "red"); // test the method area in the classes that implement IShape boolean testIShapeArea(Tester t) { return t.checkInexact(this.c1.area(), 314.15, 0.01) && t.checkInexact(this.s1.area(), 900.0, 0.01); } }

A challenge:

See if you would be able to define the following methods for the classes Circle and Square:

 // to represent a geometric shape interface IShape { // to compute the area of this shape public double area(); // to compute the distance form this shape to the origin public double distTo0(); // to increase the size of this shape by the given increment public IShape grow(int inc); // is the area of this shape is bigger than the area of the given shape? public boolean biggerThan(IShape that); // does this shape (including the boundary) contain the given point? public boolean contains(CartPt pt); }

Well, here is the solution. Study if carefully, especially the places where we decided to use helper methods in the class CartPt.

Also look carefully at the way we extend the basic template when the method argument is an instance of the class in which the method is defined — in that case we have access to all fields of the argument object and the methods these fields can invoke.