17
Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Embed Size (px)

Citation preview

Page 1: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Session 9

MultiballWorld, Refactoring Ball using Inheritence, and Intro. to

CannonWorld

Page 2: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Notes on HW #3

• Due date changed to Friday, 9/23 at 11:59 PM

• You must close the file or you might get an empty file on ‘save’.

public void save( String saveToFile ) throws IOException {

PrintWriter outputFile = new PrintWriter(new FileWriter(saveToFile ));

... <code to println to the file>

outputFile.flush(); // both of these are probably over kill

outputFile.close();

} // end save

Page 3: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Multiple Instances of “things”

• What do we need to do if we want…– Multiple BallWorlds?– Multiple Balls?

• Refer to your textbook for Budd’s examples. In class we will play with the code.

Page 4: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Multiple BallWorlds

import java.awt.Color;

public class MultipleBallWorldsApp {

public static void main( String[] args ) {

BallWorld world = new BallWorld( Color.green );

world.show();

BallWorld world2 = new BallWorld( Color.red );

world2.show();

}

}

Page 5: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Multiple Ballspublic class MultiBallWorld extends Frame {

...

private Ball [ ] ballArray;

private static final int BallArraySize = 6;

...

public MultiBallWorld (Color ballColor) {

...

// initialize object data field

ballArray = new Ball [ BallArraySize ];

for (int i = 0; i < BallArraySize; i++) {

ballArray[i] = new Ball(10, 15, 5);

ballArray[i].setColor (ballColor);

ballArray[i].setMotion (3.0+i, 6.0-i);

}

} // end MultiBallWorld constructor

public void paint (Graphics g) {

for (int i = 0; i < BallArraySize; i++) {

ballArray[i].paint (g);

// then move it slightly

ballArray[i].move();

if ((ballArray[i].x() < 0) || (ballArray[i].x() > FrameWidth))

ballArray[i].setMotion (-ballArray[i].xMotion(), ballArray[i].yMotion());

if ((ballArray[i].y() < 0) || (ballArray[i].y() > FrameHeight))

ballArray[i].setMotion (ballArray[i].xMotion(), -ballArray[i].yMotion());

}

// Adjust to slow simulation to the speed of the your computer

try { Thread.sleep( 40 ); }

catch (InterruptedException e) { System.exit( -1 ); }

// finally, redraw the frame

counter = counter + 1;

if (counter < 2000) repaint();

else System.exit(0);

}

}

Page 6: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Multiple Balls...

public void paint (Graphics g) {

for (int i = 0; i < BallArraySize; i++) {

ballArray[i].paint (g);

// then move it slightly

ballArray[i].move();

if ((ballArray[i].x()<0)|| (ballArray[i].x() > FrameWidth))

ballArray[i].setMotion (-ballArray[i].xMotion(),

ballArray[i].yMotion());

if ((ballArray[i].y()<0)||(ballArray[i].y() > FrameHeight))

ballArray[i].setMotion (ballArray[i].xMotion(),

-ballArray[i].yMotion());

} // end for

...

} // end paint

Page 7: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Refactoring BallWorld• In our current implementation, a ball has two

very different kinds of responsibilities:– to keep track of its position and size and draw it

on the screen, and– to move around the window.

• I can imagine using a ball that doesn't move, say, as a part of a stationary picture.– So these responsibilities should reside in

different classes. – But we don't want to duplicate any code, so we

will want to use inheritance.

Page 8: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Refactoring BallWorld• Both BallWorld and MultiBallWorld duplicated

the bounds-checking code! – If we must build the same functionality into two different

programs, that is a sure sign that an object should be providing that functionality as a service.

– What's worse, because the BallWorld and the MultiBallWorld do the bounds checking, they have to know the values of the Ball's instance variables -- and then change them.

– We want to design objects that provide services which don't require the client to (have to) know about the object's data. Each object should manipulate its own state. So we would prefer for the Ball to monitor its own location and control its own magnitudes.

Page 9: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Refactoring Ball Using Inheritance

• Ball - to keep track of its position and size and draw it on the screen

• MovableBall extends Ball - allows Ball to move

• BoundedBall extends MovableBall - allows ball to “bounce” off the sides of the frame– How will the Ball know about the frame?

Page 10: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Refactoring Ball Using Inheritancepublic class Ball {

private Rectangle location;

private Color color;

public Ball( int x, int y, int r ) {

location = new Rectangle( x-r, y-r, 2*r, 2*r );

color = Color.blue;

}

public void paint( Graphics g ) {

g.setColor( color );

g.fillOval( location.x, location.y, location.width,

location.height );

}

...

protected int radius() { return location.width / 2; }

protected int x() { return location.x + radius(); }

protected int y() { return location.y + radius(); }

protected Rectangle region() { return location; }

protected void moveTo(int x, int y) {region().setLocation( x, y ); }

} // end Ball

Page 11: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Refactoring Ball Using Inheritancepublic class MovableBall extends Ball {

private double dx;

private double dy;

public MovableBall( int x, int y, int r, double dx, double dy ) {

super( x, y, r );

this.dx = dx;

this.dy = dy;

}

public void move() { region().translate( (int) dx, (int) dy ); }

protected void setMotion( double ndx, double ndy ) {

dx = ndx;

dy = ndy;

}

protected double xMotion() { return dx; }

protected double yMotion() { return dy; }

} // end MovableBall

Page 12: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Refactoring Ball Using Inheritanceimport java.awt.Frame;

public class BoundedBall extends MovableBall {

private Frame myWorld;

public BoundedBall( int x, int y, int r,

double dx, double dy, Frame aWorld ) {

super( x, y, r, dx, dy );

myWorld = aWorld;

}

public void move() {

super.move();

int maxHeight = myWorld.getHeight();

int maxWidth = myWorld.getWidth();

if ( (x() < 0) || (x() > maxWidth) )

setMotion( -xMotion(), yMotion() );

if ( (y() < 0) || (y() > maxHeight) )

setMotion( xMotion(), -yMotion() );

}

}

Page 13: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

The Identity of an Object

• How can an object refer to itself?– Why would an object ever want to do this?

• How can an object refer to itself as an instance of its superclass?– Why would an object ever want to do this?

Page 14: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

Solutions

• this– Send message to self explicitly?– Refer to an instance variable with the same name as

a temporary variable.– Pass itself as an argument with a message.

• super– Refer to an inherited method with the same name as

a method defined in the class. “Respond as if...”– Initialize inherited instance variables using an

inherited constructor.

Page 15: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

An Exercise

Define a ShadowBall class. A ShadowBall is a Ball that becomes darker after every twentieth time it paints itself.

The ball’s Color object can help the ShadowBall do its task. Java Colors respond to the following message:– public Color darker()

By creating a darker version of this color.

Page 16: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

How Do I Test My Solution?

A ShadowBall is a Ball. So, I can use a ShadowBall any place that I use a Ball. So, I can test my new class in any Ball application, such as MultiBallWorld...

• Testing is necessary.• Test early and often. Test only small changes.• Make testing be as simple as possible.• Use what you have available!

Page 17: Session 9 MultiballWorld, Refactoring Ball using Inheritence, and Intro. to CannonWorld

The CannonGame Application

• What color is the cannon ball?• What is the role of dy()?• How does the CannonGame draw the cannon?• What do lv, lh, sv, and sh mean? What about sx and

sy?• How does the cannon ball follow the prescribed angle,

when we don’t pass the angle to the cannon ball?• How does the cannon ball reverse direction?• How does the game know that the ball has hit

something (either the target or the floor)?• How does the program terminate?