// CS U213 Spring 2007 // Lecture 6: January 22, 2007 /* Csu213, Monday 1/22/07 Last time: +----------------------------+ | Circle | +----------------------------+ | CartPt center | | double radius | +----------------------------+ | double area() | | boolean contains(CartPt p) | +----------------------------+ This is an 'extended' class diagram - we list the fields and method headers */ // Represents a 2D cartesian coordinate // - Needed for the Shapes defined below class CartPt{ double x; double y; CartPt(double x, double y){ this.x = x; this.y = y; } } /* Now we add a Square: +---------+ | Shape | +---------+ | / \ +---+ | +-----------+-----------+ | | | | +------------------+---------+ +------+---------------------+ | Square | | Circle | +----------------------------+ +----------------------------+ | CartPt nw | | CartPt center | | double size | | double radius | +----------------------------+ +----------------------------+ | double area() | | double area() | | boolean contains(CartPt p) | | boolean contains(CartPt p) | +----------------------------+ +----------------------------+ +------------------------+ | : | | :100 B | | : | | 200 +-------+ | |~~~~~~~~| | | | | E |50 C | | A | | | | +-------+ | | | | D | +------------------------+ The class Square... contains: CartPt p -> boolean - Is a given CartPt inside this square? */ // ** Examples ** class Examples{ Examples(){} Shape s = new Square(new CartPt(200,100), 50); Shape c = new Circle(new CartPt(225,125), 25); CartPt A = new CartPt(100, 130); // -> false CartPt B = new CartPt(220, 50); // -> false CartPt C = new CartPt(270, 140); // -> false CartPt D = new CartPt(230, 170); // -> false CartPt E = new CartPt(225, 120); // -> true boolean squareTests = ((check this.s.contains(this.A) expect false) && (check this.s.contains(this.B) expect false) && (check this.s.contains(this.C) expect false) && (check this.s.contains(this.D) expect false) && (check this.s.contains(this.E) expect true)); boolean circleTests = ((check this.c.contains(this.A) expect false) && (check this.c.contains(this.B) expect false) && (check this.c.contains(this.C) expect false) && (check this.c.contains(this.D) expect false) && (check this.c.contains(this.E) expect true)); } // Represents a Circle class Circle implements Shape{ CartPt center; double radius; Circle(CartPt center, double radius){ this.center = center; this.radius = radius; } // Method Template (or 'Inventory') // ... this.center ... -- CartPt // ... this.radius ... -- double // ... this.area() ... -- double // ... this.contains(CartPt) -- boolean // Calculate the area of this circle double area(){ return 3.1459*this.radius*this.radius; } // is the given point in this circle boolean contains(CartPt p){ return (this.sumSquares(p.x-this.center.x, p.y-this.center.y) < (this.radius*this.radius)); } // Sum the squares of the two arguments double sumSquares(double dx, double dy){ return (dx*dx+dy*dy); } } // Represents a Square class Square implements Shape{ CartPt nw; double size; Square(CartPt nw, double size){ this.nw = nw; this.size = size; } // Method Template (or 'Inventory') // ... this.nw ... -- CartPt // ... this.size ... -- double // ... this.area() ... -- double /* Because the inventory will be the same for most methods, we can place it after the contructor definition, adding new methods as we implement them These are only used incase of emergency... they are members of CartPt and a little to specific to use directly - e.g. if we wanted to change coordinate systems, we would have to change a bunch of specific 'CartPt' references */ // ... p.x ... -- double // ... p.y ... -- double // Calculate the area of this Square double area(){ return this.size*this.size; } // is the given point within this square boolean contains(CartPt p){ return ((this.nw.x < p.x) && (p.x < (this.nw.x + this.size)) && (this.nw.y < p.y) && (p.y < (this.nw.y + this.size))); } // Note that we might get rid of these references (x&y) if // there happened to be a method for CartPt... // // inInterval: is this point between the given points? // boolean inInterval(CartPt p1, CartPt p2); // This would take a little more designing of CartPt } /* Back to Scheme... ;; shape is one of: ;; -- circle ;; -- square ;; circle is ;; (make-circle posn number) ;; square is ;; (make-square posn number) ;; contains: shape posn -> boolean ;; is the given point within the given shape? (define (contains ashape p) (cond [(circle? ashape) (< (dist (circle-center ashape) p) (circle-radius ashape))] [(square? ashape) ( ... )])) The implementation in the cond corresponds to the Java methods inside the class 'variants' Because Circle/Square each implement 'contains', we can add that to our interface definition (could also add area()) */ // Represents a geometric shape interface Shape{ // is the given point within this shape? boolean contains(CartPt p); } // This is our contract; we can now write tests for Shape // Shape s = new Square( ... ); // Shape c = new Circle( ... ); /* In Scheme we decide what happens inside the 'cond,' how does this work with classes? Java knows just what to do - Above, s is of 'type' Square and also of 'type' Shape, but we say that s is an instance-of Square (not of Shape) - Java uses this information to lookup the right method for a given shape, so s.contains(...) works as expected Add a new method to Shape... Shape move(double dx, double dy); First in Scheme ;; move: shape number number -> shape ;; move the given shape by the deltas given (x&y) ;; examples: ;; (move (make-circle (make-posn 100 100) 50) 1 1) --> ;; (make-circle (make-posn 101 101) 50) ;; (move (make-square (make-posn 200 100) 50) 20 30) --> ;; (make-square (make-posn 220 130) 50) (define (move ashape dx dy) (cond [(circle? ashape) ( ... )] [(square? ashape) ( ... )])) ;; Moving the point is a little messy ;; (make-posn (+ (posn-x (circle-center ashape) dx)) ;; (+ (posn-y (circle-center ashape) dy))) ;; So we should make a helper function ;; move-posn: posn number number -> posn ;; move a posn by dx and dy... ;; (define (move-posn p dx dy) ;; (make-posn (+ (posn-x p dx)) ;; (+ (posn-y p dy)))) For Java we need to: - Add the method to our interface (contract/purpose) - Examples!! - Add it to our 'global' templates (Circle and Square) - Implement it for our variants: Circle and Square Main Points/Summary * Scheme 'cond' corresponds to our Java variants - Method header (contract) goes into the common interface - Each clause becomes the implementation of our method - Java does the work of the 'cond' for us! */ /*