Upload
andrew-davis
View
217
Download
2
Embed Size (px)
Citation preview
Object Oriented Programming
Lecture 5:Refactoring by Inheritance and Delegation - A simple Design Pattern for animation applets, A Generic Function Plotterwww.hh.se/staff/jebe/oop2006/main.html
Setting the environment variables for JDK in UNIX
set the CLASSPATH environment variable in your ”.cshrc.private” file
If the CLASSPATH is not set: setenv CLASSPATH ~/test/myclasses
If the CLASSPATH already is set: setenv CLASSPATH
~/test/myclasses::~/classdir/test2::etc
The Applets Design Pattern
Java applets embedded in web pages Applets are downloaded from a web
server and executed on the client in a web browser or appletviewer
Applets must extend the Applet class Can be found in java.applet package
Embedding the applets in HTML The simplest form of applet HTML tags:<applet code = byte-code filename
width in pixels
height in pixels>
</applet> Will make the browser execute the applet
in the webpage context
Interaction between the context and applet
An applet interacts with the context according to a contractual interface
Init() – initialize the applet when it is initially loaded
Start() – activates the applet and is invoked when entering the webpage
Stop() – deactivates the applet Destroy() - destroys the applet when
the webpage is discarded
Simple animation applet
The applet displays the current time HH:MM:SS
In order draw on the screen we must overload the paint() method
Requires a Thread to control the Animation
Problem: We can’t extend both Applet and Thread...?
The Runnable Interface The Solution: Java provides the Runnable
Interface Implemented by a class that should run in a
Thread By implemententing Runnable
A class can pass itself as argument to the Thread() constructor
We need to define the run() method that is invoked when starting the Thread
The start() method
public void start(){if(clockThread != null){
clockThread = new Thread(this);clockThread.start();
}}
Public void stop()clockThread = null;
Calls run()!
Kill the Thread!
Controlling the Animation -the run() method
public void run(){while(Thread.currentThread() == clockThread){
repaint();try{Thread.currentThread().sleep(1000);}catch(InterruptedException e){};
}}
Calls paint() to draw the time on the screen
Sleep 1 second before redrawing!
Drawing the time on screen- the paint() method
Public void paint(graphics g){
...
g.setFont(font);
g.setColor(color);
g.drawString(hour + ”:” + minute + ”:” + second);
}
Idiom: Animation Applet An Idiom: ”How we can program a generic
template that can be reused for a recurring problem” It should be possible to customize and adapt
Applets can produce some graphical output that changes without interaction from the user (animation)
Using the Animation Applet Idiom: extend AnimationApplet and redefine the paint
method
Double buffering
If painting directly on the screen, the screen will ”flicker”
Double buffering can be used to solve this problem
Double buffering 1 ”draw invisibly” in a background buffer 2 Then update the screen with the buffer
Double buffering When calling repaint() it will
automatically call the update() update() will clear the screen using
the background color and call the paint method paint(Graphics g);
Solution: To avoid the the ”flicker” - override the update method
Instead of clearing - let update(); paint the buffered image
A Generic Double buffered Animation Applet
What do we need to do? We need to create a background image. We need to override the update()
method. We need a method to do the drawing in
the background image. We can extend and reuse the simple
Applet to define a generic Animation Applet
DoubleBuffered Animation Applet – Refactoring the applet
Public class abstract DBAnimationApplet extends AnimationApplet{
...
Graphics backGraphics;
Image backImage;
Dimension dim;
Boolean doubleBuffered;
...
}
The init() method
Public final void init(){dim = getSize();backImage = new Image(dim.width, dim.height);backGraphics = backImage.getGraphics();initAnimator();
}
Protected void initAnimator(){}
The update() method...Public final void update(Graphics g){
if(doubleBuffered){paintFrame(backGraphics);g.drawImage(backImage,0,0,this);
}elsesuper.update();
}
Public void paint(Graphics g){paintFrame(g);
}
The constructors
Protected DBAnimationApplet(boolean db){
this.doubleBuffered = db;}
Protected DBAnimationApplet(){this.doubleBuffered = true;
}
How do we use the DoubleBuffered Animation Applet?
1. Extend the DBAnimationApplet 2. Use the appropriate constructor to
choose doublebuffer/not doublebuffer 3. Define the abstract paintFrame()
method ...and that is it
Design by Abstraction
Designing generic components Reusable Extensible
Using: Abstract classes Interfaces Design patterns (and idioms)
Without having to modify the code!
Example
An applet for plotting functions.
Should be easy to adapt for different functions
A generic applet that captures the common code
A generic plotter
The class Plotter
Factoring by inheritance:
public class Plotter extends Japplet
public init: read parameters form html-file size parametersscaling parameters
public paint: draw the coordinate axis draw the function graph in the interval given by the parameters!
The class Plotter
What function?
A function can be implemented by a method:
public double func(double x){???}
better:
protected abstract double func(double x);
which also forces the class to be abstract! It has to be extendedfor instances to be allowed!public abstract class Plotter extends Japplet
Plotting a function
public class CosPlotter extends Plotter{ protected double func(double x){
return Math.cos(x); }} Or
public class SinPlotter extends Plotter{ protected double func(double x){
return Math.sin(x); }}
Looking inside Plotter
public abstract class Plotter extends Japplet{
private int w,h,xorigin,yorigin,xratio,yratio;private Color color = Color.black;
protected abstract double func(double x);
public void init(){w = Integer.parseInt(getParameter(“width”));h = Integer.parseInt(getParameter(“height”));xorigin = ...yorigin = ...xratio = ...yratio = ...
}
Looking inside Plotter
public void paint(Graphics g){drawCoordinates(g);plotFunction(g);
}
private void plotFunction(Graphics g){for(int px = 0; px < dim.width; px ++){ try{
double x =(double)(px - xorigin)/(double)xratio;double y =func(x);int py = yorigin - (int)(y * yratio);g.fillOval(px-1,py-1,3,3);
}catch(Exception e){}}
}
Factoring by inheritance
Design pattern: TEMPLATE
In the abstract class a template method calls (plotFunction)
a hook method (func) that is left abstract!
Factoring by delegation
The class MultiPlotter
public class MultiPlotter extends Japplet
public init as before: read parameters. public paint as before: draw coordinates and the function in the interval given by the params.
What function? A function can be implemented by an object that can do apply(double)! private Function f;
The interface Function
We need a type Function for objects that can do
double apply(double x)
Now, we want this method to behave sometimes as cos, sin, or other function. We leave the implementationthus unspecified and just define
public interface Function{ public double apply(double x);}
MultiPlotter
We can now plot a number of functions in the same applet (By having an array with Functions and an array with Colors)
We have to offer a method to add functions
We have to decide when/how to add the functions.
MultiPlotter
Let the class that adapts (extends) MultiPlotter define init() where
Parameters are read Functions are added (using the method
for doing so) A bad thing:
what happens if the programmer forgets to read the parameters?
Let init be a template method and use a hook to allow the new class to add functions!
MultiPlotter
public abstract class MultiPlotter extends Japplet
private int w, h, xorigin, yorigin, xratio, yratio; private Function [] functions; private Color [] colors;
public final void init(){/* read parameters; */functions = new Function[max];colors = new Color[max];initMultiPlotter();
}
protected abstract void initMultiPlotter();
MultiPlotter.plotFunctions
private void plotFunctions(Graphics g){ for(int i = 0; i < numOfFunctions; i++){ g.setColor(colors[i]); for(int px = 0; px < dim.width; px ++){
try{double x = (double)(px ...double y = functions[i].apply(x);int py = yorigin - ...g.fillOval(px-1,py-1,3,3);
}catch(Exception e){}}
}}
Plotting sin and cos
public class SinCos extends MultiPlotter{ protected void initMultiPlotter(){ addFunction(new Sin(),Color.red);
addFunction(new Cos(),Color.blue); }}
public class Cos implements Function{ public double apply(double x){ return Math.cos(x); }}
Plotting Sin and Cos
Design Guidelines
Maximize adaptability (extensibility)The more extensible a component is, the better chances it will be reused
Minimize risk for missuse!(make init a final method and force the definition of initMultiPlotter instead of allowing for redefinition of init!)
Factoring by delegation
Design pattern: STRATEGY
In the context (the general class, MultiPlotter) one or more instances of strategy objects
(Function[] functions) some concrete strategies (classes implementing the strategy: Cos, Sin)