660 likes | 783 Views
Lecture I - Polymorphism. Unit I1 - Introduction to Polymorphism. Polymorphism. Recall that method invocation is virtual The actual method called depends on the runtime type Thus the behavior obtained using x.m() takes a different form according to the subtype that x has.
E N D
Lecture I - Polymorphism Unit I1 - Introduction to Polymorphism
Polymorphism • Recall that method invocation is virtual • The actual method called depends on the runtime type • Thus the behavior obtained using x.m() takes a different form according to the subtype that x has. • This can be used for customizing the behavior of a piece of code that deals with objects of the super-class type without modifying the code itself.
Factoring out variations to the sub-classes Kid k; … // k = Boy or Girl if (k instanceOf Boy) … // draw in blue else … // draw in red … // more unisex code Kid Boy Girl Kid k; … // k = Boy or Girl Color c = k.getColor(); … // all unisex code
Overriding getColor() class Kid { // … public Color getColor() { return Color.purple; } } class Boy extends Kid { public Color getColor() { return Color.blue; } } class Girl extends Kid { public Color getColor() { return Color.red; } }
Documenting getColor() /** * Returns the color in which to graphically * represent the kid. Default is purple. */ class Kid { // … public Color getColor() { return Color.purple; } }
Abstract Classes • Sometimes we don’t want to give any implementation for a super-class method, but rather force all subclasses to provide an implementation. • We need to make the definition of the method in the super-class as to allow polymorphism in code that deals with instances of the super-class compile-time type. • We can define the method as being abstract, and thus force all subclasses to implement it. • In this case there can be no instances of the super-class type (but only of subclass of it), and the super-class must be defined as abstract.
Abstract version of Kid abstract class Kid { // … abstract public Color getColor(); } class Boy extends Kid { public Color getColor() { return Color.blue; } } class Girl extends Kid { public Color getColor() { return Color.red; } }
Interfaces • The most extreme form of an abstract class is one that only has obligations: • No fields • All methods are abstract • This case is very important as it simply formalizes an interface. • Java has a special syntax for this called “Interface”. • A class can only extend a single direct super-class, but can implement any number of Interfaces.
Lecture I - Polymorphism Unit I2 - Heterogeneous Collections
Lesson or Unit Topic or Objective Using Heterogeneous Collections
Heterogeneous Collections • When we have a collection of objects of an object type, some of the objects in the collection may have a subclass run-time type. • Thus such a collection will have heterogeneous types. • This may be used just to hold the objects together, or also may apply polymorphic behavior • When objects are taken out of the collection, they need to be narrowed into the subtype you want to work with
SwitchPanel Heterogeneous Collection • Suppose, for example, that we want a class SwitchPanel that represents a panel of switches. Some of the switches in the panel are simple switches and some are adjustable switches. • Suppose also that we’ve added the method getConsumption() in class Switch that returns the electrical consumption of the switch (which is 0 if the switch is off and maxPower if the switch is on) • This method was overridden in class AdjustableSwitch (the consumption is 0 if the switch is off, or level * maxPower / 100 if it is on).
getConsumption() public class Switch { // ... same implementation as before public double getConsumption() { return isOn() ? maxPower : 0; } } public class AdjustableSwitch extends Switch { // ... same implementation as before public double getConsumption() { returnsuper.getConsumption() * level / 100; } }
Switch Panel – design idea • When implementing our SwitchPanel class, we would like to store switches of both kinds in a single array, so we can easily write code that operates on both kinds of switches. • For example, suppose we want to implement a method getTotalConsumption() in class SwitchPanel that will compute the total electrical consumption of all the switches in the panel, whether they are adjustable switches or regular switches.
SwitchPanel public class SwitchPanel { private Switch[] switches; privateint numSwitches; public SwitchPanel(int maxSwitches) { switches = new Switch[maxSwitches]; numSwitches = 0; } publicvoid addSwitch(Switch s){ switches[numSwitches++] = s; } public double getTotalConsumption() { double total = 0.0; for (int i = 0; i < switches.length; i++) total += switches[i].getConsumption(); return total; } }
Heterogeneous Collections in the Java API • Collection classes in the Java API contain arbitrary Objects. • One of the simplest is java.util.Vector. • A vector is an ordered collection of objects. • You may add or remove objects from the vector at any position • The size of a Vector grows and shrinks as needed to accommodate adding and removing items after the Vector has been created.
Animals class Cat { public String toString() { return“meaw”; } } class Dog { public String toString() { return“roff”; } } class Mouse { public String toString() { return“squeak”; } public String complain() { return“Ouch” ; } }
Vector of Animals class AnimalSounds { public static void main(String[] args) { Vector v = new Vector(); v.addElement(new Cat()); v.addElement(new Mouse()); v.addElement(new Dog()); for (int i = 0; i < v.size(); i++){ System.out.println(v.elementAt(i)); if (v.elementAt(i) instanceof Mouse) { Mouse m = (Mouse) v.elementAt(i); System.out.println(m.complain()); } } } }
Lecture I - Polymorphism Unit I3 - Abstract Classes
Paint Brush Application Paint Brush Paint Brush application
Paint-brush application design • Consider the design of a paint-brush application: • We want to represent the drawing as a collection of objects, each represents a certain figure. • We want to represent each type of figure with a suitable class. Objects of these classes will know how to draw themselves. • The classes have common properties (location, size, color, ...) and common behaviors (moveTo(), resize(), ...). • We want to have a common super-class for all these classes that will define all the common properties and behaviors.
A class hierarchy for Figures moveTo(x,y) moveBy(dx,dy) resize(factor) setLineColor(color)... Figure Ellipse Rectangle draw() contains(x,y) draw() contains(x,y)
Figure class /** * A geometrical figure. A Figure has a location and size * it can draw itself on the screen ... */ public class Figure { // The top-left corner of the rectangular bounding box // of the figure protected int x,y; // The dimensions of the figure (of the bounding box // of the figure) protected int width, height; // The color of the border of the figure private Color lineColor; // ... other properties
Figure -- methods public Figure(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } public Color getLineColor() { return lineColor; } publicvoid moveTo(int x, int y) { this.x = x; this.y = y; } publicvoid moveBy(int dx, int dy) { moveTo(x+dx, y+dy); }
Rectangle public class Rectangle extends Figure { public Rectangle(int x, int y, int width, int height) { super(x, y, width, height); } public void draw() { Turtle painter = new Turtle(); painter.setLocation(x,y); painter.setAngle(0); painter.tailDown(); painter.moveForwards(width); painter.turnRight(90); painter.moveForwards(height); painter.turnRight(90); painter.moveForwards(width); painter.turnRight(90); painter.moveForwards(height); painter.hide(); } }
Abstract classes • We’ve used class Figure to ease our design. It is also correct from the point of view of our abstraction • However, note that we will never want to create instances of class Figure, only of subclasses of this class! • To denote this, we define the class Figure as an abstract class.
Figure as an abstract class /** * A geometrical figure. A Figure has a location and size * it can draw itself on the screen ... */ publicabstractclass Figure { // The top-left corner of the rectangular area that // contains the figure protected int x,y; // ... Now, we cannot create instances of class Figure, only instances of subclasses of Figure which are not definedas abstract.
The draw() method • What are the benefits of defining a class abstract? • Note that the draw() method appears in the interface of all subclasses of class Figure, but is implemented differently in each one of them. • If we have defined this method in class Figure, it was to say that every figure can draw itself. We would then override this method in every specific subclass and could draw an heterogeneous collection of figures with a single loop.
Using Figures public class PaintBrushPicture { private Vector figures; public PaintBrushPicture() { figures = new Vector(); } public void addFigure(Figure figure) { figures.addElement(figure); } public void drawPicture() { for (int i=0; i<figures.size(); i++) { ((Figure)figures.elementAt(i)).draw(); } } // ... }
Abstract methods • But how should we define the method draw() in class Figure? There is no meaning for drawing an abstract figure! • We can make a workaround and write an empty implementation for draw() in Figure. This is NOT clean! It is a patch! Moreover what about methods like contains() ? • The catch is that we do not have to implement this method, because no one can create instances of class Figure! Instead we declare the method as abstract and omit its body.
Figure – abstract methods /** * A geometrical figure. ... */ public abstract class Figure { //... state variables as before /** * Draws this figure. */ public abstract void draw(); /** * Checks whether a given point is in the * interior of this figure. */ public abstract boolean contains(int x, int y);
ChessPiece class Hierarchy moveTo(x,y) moveBy(dx,dy) getLocation() getPossibleMoves()... ChessPiece . . . Pawn Rook Knight getPossibleMoves() getPossibleMoves() getPossibleMoves()
Electronic Gate class hierarchy getNumberOfInputs() getInputVoltage(i) setInputVoltage(i) getOutputVoltage() process() ElectronicGate . . . AndGate OrGate NotGate process() process() process()
Lecture I - Polymorphism Unit I4 - Interfaces
Interfaces • An Interface is a “totally abstract” class • No fields • All methods are abstract • It thus defines an interface that must be implemented by each one of its sub-classes • In Java, a class may implement many interfaces, even though it may extend only a single super-class • When should interfaces be used for? • What we view in our abstraction as a set of obligations • Whenever we would need multiple inheritance otherwise
Movable Shape public interface Movable { public Point getCenter(); public void move(float deltaX, float deltaY); }
Point public class Point implements Movable { private float x, y; public Point(float x,float y) { this.x = x;this.y = y; } public float getX() { return x; } public float getY() { return y; } public Point getCenter() { returnthis; } publicvoid move(float deltaX, float deltaY) { x += deltaX; y += deltaY; } }
Rectangle public class Rectangle implements Movable { private float top, bottom, left, right; public Rectangle(float t,float b,float l,float r) { top = t ; bottom = b ; left = l ; right = r ; } public float getCenter() { return new Point((top+bottom)/2,(left+right)/2 ); } public void move(float deltaX, float deltaY) { top += deltaY ; bottom += deltaY ; left += deltaX ; right += deltaX ; } }
Circle public class Circle implements Movable { private Point center; private float radius; public Circle(Point p, float r) {center = p;radius = r} public float getCenter() { return center; } public float getRadius() { return radius; } public void move(float deltaX, float deltaY) { center.move(deltaX, deltaY) } }
MovingExample public class MovingExample { public static void main(String[] args) { Rectangle r = new Rectangle(10.0, 20.0, 30.0, 40.0); moveDownToZone(r); Circle c = new Circle(new Point(10.0, 20.0) , 5.0); moveDownToZone(c); } public static void moveDownToZone(Movable s){ final float zoneTop = 200.0; final float step = 10.0; while ( s.getCenter().getY() < zoneTop ) s.move(0.0, step); } }
Paint Brush Application II Recall the paint-brush application example. Supposewe want now to be able to paint also pixels and lines. Paint Brush Paint Brush application
The need for the Drawable Interface Drawable Object Point Line Figure Polygon Rectangle Pixel Ellipse
The Drawable Interface Drawable view getLocation() moveTo() moveBy() draw() toString() ... getEdgeSize() setEdgeSize() Figure view Rectagle Rectangle view Object view
Drawable /** * An interface for classes whose instances know how * to draw themselves on a graphical window. */ publicinterface Drawable { /** * Draws this object. */ public void draw(); }
Pixel /** * Represents a pixel on a graphical area. */ public class Pixel extends Point implements Drawable { ... /** * Draws this pixel on the screen. */ public void draw() { ... } ... }
Figure implementing Drawable /** * A geometrical figure. A Figure has a location and * size it can draw itself on the screen ... */ public abstract class Figure implements Drawable { // As before ... // No need to redefine draw()
Using Drawable /** * A picture made of geometrical figures. */ public class PaintBrushPicture { // The elements (figures) that compose this picture private Drawable[] elements; ... /** * Draws this picture. */ public void drawAll() { for (int i=0; i< elements.size(); i++) elements[i].draw(); }
Implementing multiple interfaces /** * A geometrical figure. A Figure has a location and * size, it can draw itself on the screen ... */ public abstract class Figure implements Drawable, Moveable { ... public void move(int deltaX, int deltaY) { this.x += deltaX; this.y += deltaY; } ...
Fighters public interface Fighter { public void hit(); } public class KungFuFighter implements Fighter { public void hit() { System.out.print(“trach! ”); } } public class Boxer implements Fighter { private boolean nextPunchLeft; public Boxer(boolean leftHanded){nextPunchLeft=leftHanded;} public void hit(){ System.out.print(nextPnchLeft ? “left pow! ” : “right pow! ”); nextPunchLeft = !nextPunchLeft; } }
FightingArmy public class FightingArmy { public static void main(String[] args) { Fighter[] soldiers = new Fighter[10]; for ( int j = 0 ; j < 10 ; j++ ) if ( Math.random() > 0.5 ) soldiers[j] = new Boxer(true); else soldiers[j] = new KungFuFighter(); for ( int j = 0 ; j < 10 ; j++ ) { System.out.print(“Soldier ” + j + “:”); for (int k = 0 ; k < 5 ; k++) soldiers[j].hit(); System.out.println(); } } }