// CS U213 Spring 2007 // Lecture 15: February 12, 2007 // Part I: /* We continue the examples from last time... +-------------------------+ | Star | +-------------------------+ | Posn loc | | int lifespan | +-------------------------+ | boolean draw(Canvas c) | | Star moveStar() | +-------------------------+ Previous versions of our methods: boolean draw(Canvas c){ if(this.lifespan > 0) return drawDisk(this.loc, 3, new Blue()); else return drawDisk(this.loc, 3, new Black()); } Star moveStar(){ if(this.lifespan > 0) return new Star(new Posn(this.loc.x, this.loc.y+3), this.lifespan-1); else return new Star(new Posn(this.loc.x, this.loc.y+4), this.lifespan); } Note that these repeat a lot of code... and 'if's are kind of messy so we try to abstract... */ /* First, we take care of having to know internals of a Posn... by extending Posn, so we can add methods to the library class +-------------------------+ +---+ | \ / | +-----v---+ +-----------------+-----------------+ | Posn | | CartPt | +---------+ +-----------------------------------+ | int x | +-----------------------------------+ | int y | | CartPt translate(int dx, int dy) | +---------+ +-----------------------------------+ */ // Imports... import draw.*; import colors.*; import geometry.*; // Represents a movable Cartisian Coordinate class CartPt extends Posn{ CartPt(int x, int y){ super(x,y); } // Move this point by (dx,dy) CartPt translate(int dx, int dy){ return new CartPt(this.x+dx, this.y+dy); } } /* - Update Star to use our new class and method - Introduce a new class, BurnedStar, with a lifespan always 0 - Add a field, Color, to both classes Because of all these new fields, we Overload the constructor with some defaults... */ // Represents a falling Star class Star{ CartPt loc; Color color; int lifespan; // Full constructor with all fields Star(CartPt loc, Color color, int lifespan){ this.loc = loc; this.color = color; this.lifespan = lifespan; } // Default for a normal Star Star(CartPt loc, int lifespan){ this(loc, new Blue(), lifespan); } // Move this Star down, decrease its lifetime, and convert it // to a BurnedStar if needed Star move(){ if(this.lifespan > 0) return new Star(this.loc.translate(0,3), this.lifespan-1); else return new BurnedStar(this.loc).move(); } // Draw this Star on the given Canvas boolean draw(Canvas c){ return c.drawDisk(this.loc, 3, this.color); } } // Represents a 'dead' Star which has Burned out class BurnedStar extends Star{ BurnedStar(CartPt loc){ super(loc, new Black(), 0); } // Move this BurnedStar down Star move(){ return new BurnedStar(this.loc.translate(0,4)); } // Draw this Star on the given Canvas boolean draw(Canvas c){ return c.drawDisk(this.loc, 3, this.color); } } class Examples{ Star s1 = new Star(new CartPt(100,100), 3); Star s2 = new Star(new CartPt(20,30), 1); Star s3 = new Star(new CartPt(50,50), 0); Star bs1 = new BurnedStar(new CartPt(70,40)); Star bs2 = new BurnedStar(new CartPt(10,60)); boolean moveTests = ((check s1.move() expect new Star(new CartPt(100,103), 2)) && (check s2.move().move() expect new BurnedStar(new CartPt(20,37))) && (check bs1.move() expect new BurnedStar(new CartPt(70,44)))); Canvas c = new Canvas(220, 200); boolean testDraw = (c.show() && doMove(new Star(new CartPt(40, 50), 17), c, 20) && doMove(new Star(new CartPt(70, 50), 24), c, 20) && doMove(new Star(new CartPt(100,50), 10), c, 20) && doMove(new Star(new CartPt(130,50), 20), c, 20) && doMove(new Star(new CartPt(160,50), 6), c, 20) && doMove(new BurnedStar(new CartPt(190,50)), c, 20)); // Move the given Star 'down' the Canvas, 'num' times boolean doMove(Star s, Canvas c, int num){ return ((num < 0) || (s.draw(c) && doMove(s.move(), c, num-1))); } } /* Part II: Constructor Overloading vs. Method Overloading Overriding is when a subclass implements the same method signature - same name - same return type - same argument types and order Previously we had shapes, Shape/Circle/Square with the sameCircle method: // In class Shape boolean sameCircle(Circle c){ return false; } // In class Circle boolean sameCircle(Circle c){ return ((c.loc.x == this.loc.x) && (c.loc.y == this.loc.y) && (c.radius == this.radius); } Here we override the sameCircle method so that our new method will be called whenever we have a Circle, and the old one if we have any other shape Overloading is when we change the argument list types or order */ // Represents a Library Book class Book{ String title; String author; int year; // Simple Constructor Book(String title, String author, int year){ this.title = title; this.author = author; this.year = year; } // Constructor with a default year // we call the simple constructor using this(...) // It must be the first statement in the constructor Book(String title, String author){ this(title, author, 2007); } // Constructor with a default author Book(String title, int year){ this(title, "MF", year); } // Constructor with a default author and year // we call the default year constructor the same way Book(String title){ this(title, "MF"); } // Note that we cannot do this... /* Book(String author){ this("HtDC", author, 2007); } */ // Since the argument types are the same as above } class Examples2{ Book b1 = new Book("NS","JA",2007); Book b2 = new Book("HR","TH",2007); Book b3 = new Book("HtDC","MF",2007); Book b4 = new Book("NS","JA"); Book b5 = new Book("HR","TH"); Book b6 = new Book("HtDC"); } /* We can also do calculations in constructors... We do this to provide a convenience constructor for the user. */ // Represents a Temperature class Temp{ int degF; // Simple Constructor Temp(int degF){ this.degF = degF; } // Takes in the scale, one of 'c' or 'f' // and converts it to fahrenheit Temp(int deg, char scale){ if(scale == 'f') this.degF = deg; else this.degF = (9*deg/5)+32; } } class Examples3{ Temp freeze = new Temp(32); Temp boil = new Temp(212); Temp c0 = new Temp(0,'c'); Temp c100 = new Temp(100,'c'); Temp f32 = new Temp(32,'f'); boolean test = ((check this.freeze.degF expect this.c0.degF) && (check this.boil.degF expect this.c100.degF) && (check this.f32.degF expect this.freeze.degF)); }