MultiballWorld CannonWorld

advertisement
Session 8
Lab 4 comments, MultiballWorld,
Refactoring Ball using Inheritence,
and Intro. to CannonWorld
Notes on HW #3
• 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();
outputFile.close();
} // end save
// both of these are probably over kill
The Role of Inheritance in Java
Graphics
“Don’t call us. We’ll call you.”
Without inheritance, we would have to
understand many details of how windows work
and how they interact with the operating system.
• Some of those details are over our heads at this
point. We don’t know enough OOP or Java yet.
• Even if we could understand them (and we will
eventually), we don’t care about them.
The Role of Inheritance in Java
Graphics
With inheritance, a BallWorld can act as a
“regular” Frame when we don’t care about the
details and as a special kind of Frame when we
do.
But there is more to it than that. Not only does
BallWorld inherit a lot of individual methods that
we use — but many of the methods in Frame
call the methods we implement in BallWorld!
Example: Frame manipulation
Your BallWorld should be able to handle:
• Frame relocation
• Frame resizing
• Minimizing/Maximizing
• Etc….
But wait, I didn’t write any code to handle
this…
Example: The show() and
paint() Methods
But there is more to it than that. Not only does
BallWorld inherit a lot of individual methods that
we use — but many of the methods in Frame
call the methods we implement in BallWorld!
Consider how the BallWorld program displays its output:
// BallWorld
public void paint( Graphics g ) {
aBall.paint( g );
aBall.move ();
...
counter = counter + 1;
if ( counter < 2000 )
repaint();
else
System.exit(0);
Example: The show(), paint(), and
repaint() Methods
// In BallWorldApplication
BallWorld world=new BallWorld(Color.red);
world.show();
// In BallWorld
public void paint( Graphics g ) {
aBall.paint( g );
aBall.move ();
...
counter = counter + 1;
if ( counter < 2000 )
repaint();
else
System.exit(0);
}
// In Ball
public void paint( Graphics g ) {
g.setColor( color );
g.fillOval( location.x, location.y,
location.width, location.height );
• show() inherited from Frame
• show() calls paint(Graphics g)
of BallWorld
• the Graphics object g passed by
show() has the ability to draw a
host of items to the Frame
• the Graphics object g is passed
to paint(g) of aBall
• Ball’s paint uses the Graphics
object to put a fillOval on the
screen
“Don’t call us. We’ll call you.”
This is a simple example of... multiple objects collaborating to
solve a problem
It is also an even better example of... writing a program by
filling in the details (e.g., paint()) of another program (e.g.,
Frame) that already does a lot of work
The Java AWT is also an example of a framework, a group
of classes that work together to provide generic solutions
in an application domain, which programmers can extend
to provide specific solutions.
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.
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();
}
}
Multiple Balls
public 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);
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
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.
Refactoring BallWorld
• The original 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.
– Maintain in single place, e.g., adding Insets checking
– 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.
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?
Refactoring Ball Using Inheritance
public 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
protected
protected
protected
protected
} // end Ball
int radius() { return location.width / 2; }
int x() { return location.x + radius(); }
int y() { return location.y + radius(); }
Rectangle region() { return location; }
void moveTo(int x, int y) {region().setLocation( x, y ); }
Refactoring Ball Using Inheritance
public 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
Refactoring Ball Using Inheritance
import 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() );
}
}
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?
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.
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.
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!
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?
Download