/* --- CSU213 Fall 2006 Lecture Notes --------- Copyright 2006 Viera K. Proulx Lecture 10: September 27, 2006 Abstracting over data Definitions Part 2: Lifting fields, Lifting methods */ /* +---------------------------------+ | IShape | +---------------------------------+ +---------------------------------+ | double area() | | double distTo0() | | boolean biggerThan(IShape that) | +--------------------------------+ | / \ --- | +---------------------------------+ | AShape | +---------------------------------+ +-------------------| CartPt loc | | | String color | | +---------------------------------+ | | abstract double area() | | | double distTo0() | | | boolean biggerThan(IShape that) | | +---------------------------------+ | | | / \ | --- | | | ------------------------------------- | | | | +---------------------------------+ +---------------------------------+ | | Circle | | Square | | +---------------------------------+ +---------------------------------+ | | int radius | | int size | | +---------------------------------+ +---------------------------------+ | | double area() | | double area() | | | double distTo0() | +---------------------------------+ | +---------------------------------+ +----+ | v +--------+ | CartPt | +--------+ | int x | | int y | +--------+ */ // to represent a geometric shape interface IShape { // to compute the area of this shape double area(); // to compute the distance form this shape to the origin double distTo0(); // is the area of this shape is bigger than the area of the given shape? boolean biggerThan(IShape that); } /*---------------------------------------------------------------------- Lifting fields: The abstract class contains the two fields common to all shapes: The location of the shape on canvas, and its color. Notice, that the common color works only when we work with simple shapes. If we add a class that represents a combination of two shapes, the combo shapes will no longer have a unique color. Lifting methods: The method double area() is defined for both classes, but the body is different. The abstract class cannot implement the method, but declares the method as abstract. This establishes a requirement that every class that extends the abstract class must implement this method. The method double distTo0() is defined for both classes, but the body is different. However, if we defined another class to represent a rectangle with a NW corner, the method body for Square and Rectangle would be the same. If most of the classes in the union implement the method in the same we can lift the method definition to the abstract class. We then omit the definition from all classes, except those where the implementation is different. In those cases we say that the new definition overrides the old one. --------- The method boolean biggerThan(IShape that) has identical definition in both classes. We lift the definition to the abstract class and omit it entirely from the derived classes. ---------------------------------------------------------------------*/ // to represent a geometric shape abstract class AShape implements IShape{ CartPt loc; String color; AShape(CartPt loc, String color){ this.loc = loc; this.color = color; } // to compute the area of this shape abstract double area(); // to compute the distance form this shape to the origin double distTo0(){ return this.loc.distTo0(); } // is the area of this shape is bigger than the area of the given shape? boolean biggerThan(IShape that){ return this.area() >= that.area(); } } // to represent a circle class Circle extends AShape { int radius; Circle(CartPt loc, int radius, String color) { super(loc, color); this.radius = radius; } /* // ** TEMPLATE ** public returnType methodName() { ... this.loc ... -- CartPt ... this.radius ... -- int ... this.color ... -- String ... this.area() ... -- double ... this.distTo0() ... -- double ... this.biggerThan(AShape that) ... -- boolean */ // to compute the area of this shape double area(){ return Math.PI * this.radius * this.radius; } // to compute the distance form this shape to the origin double distTo0(){ return this.loc.distTo0() - this.radius; } } // to represent a square class Square extends AShape { int size; Square(CartPt loc, int size, String color) { super(loc, color); this.size = size; } /* // ** TEMPLATE ** returnType methodName() { ... this.loc ... -- CartPt ... this.size ... -- int ... this.color ... -- String ... this.area() ... -- double ... this.distTo0() ... -- double ... this.biggerThan(AShape that) ... -- boolean } */ // to compute the area of this shape double area(){ return this.size * this.size; } } /* +--------+ | CartPt | +--------+ | int x | | int y | +--------+ */ // to represent a Cartesian point class CartPt { int x; int y; CartPt(int x, int y) { this.x = x; this.y = y; } // to compute the distance form this point to the origin double distTo0(){ return Math.sqrt(this.x * this.x + this.y * this.y); } // to compute the distance form this point to the given point double distTo(CartPt pt){ return Math.sqrt((this.x - pt.x) * (this.x - pt.x) + (this.y - pt.y) * (this.y - pt.y)); } } class Examples { Examples() {} CartPt pt1 = new CartPt(0, 0); CartPt pt2 = new CartPt(3, 4); CartPt pt3 = new CartPt(7, 1); IShape c1 = new Circle(new CartPt(50, 50), 10, "red"); IShape c2 = new Circle(new CartPt(50, 50), 30, "red"); IShape c3 = new Circle(new CartPt(30, 100), 30, "blue"); IShape s1 = new Square(new CartPt(50, 50), 30, "red"); IShape s2 = new Square(new CartPt(50, 50), 50, "red"); IShape s3 = new Square(new CartPt(20, 40), 10, "green"); // test the method distTo0 in the class CartPt boolean testDistTo0 = (check this.pt1.distTo0() expect 0 within 0.001) && (check this.pt2.distTo0() expect 5 within 0.001); // test the method distTo in the class CartPt boolean testDistTo = (check this.pt1.distTo(this.pt2) expect 5 within 0.001) && (check this.pt2.distTo(this.pt3) expect 5 within 0.001); // test the method area in the class Circle boolean testCircleArea = check this.c1.area() expect 314.15 within 0.01; // test the method grow in the class Circle boolean testSquareArea = check this.s1.area() expect 900 within 0.01; // test the method distTo0 in the class Circle boolean testCircleDistTo0 = (check this.c1.distTo0() expect 60.71 within 0.01) && (check this.c3.distTo0() expect 74.40 within 0.01); // test the methdod distTo in the class Circle boolean testSquareDistTo0 = (check this.s1.distTo0() expect 70.71 within 0.01) && (check this.s3.distTo0() expect 44.72 within 0.01); // test the method biggerThan in the class Circle boolean testCircleBiggerThan = (check this.c1.biggerThan(this.c2) expect false) && (check this.c2.biggerThan(this.c1) expect true) && (check this.c1.biggerThan(this.s1) expect false) && (check this.c1.biggerThan(this.s3) expect true); // test the method biggerThan in the class Square boolean testSquareBiggerThan = (check this.s1.biggerThan(this.s2) expect false) && (check this.s2.biggerThan(this.s1) expect true) && (check this.s1.biggerThan(this.c1) expect true) && (check this.s3.biggerThan(this.c1) expect false); }