Session 18 Lab 9 Re-cap, Chapter 12: Polymorphism & Using Sound in Java Applications Decorated Ball import java.awt.*; public class DecoratedBall extends MovableBall { private MovableBall workerBall; public DecoratedBall( MovableBall aBall ) { super(); workerBall = aBall; } protected MovableBall worker() { return workerBall; } // *** MESSAGES DELEGATED TO THE INSTANCE VARIABLE public void move() { workerBall.move(); } public void paint( Graphics g ) { workerBall.paint( g ); } public void setColor( Color newColor ) { workerBall.setColor( newColor ); } public Color color() { return workerBall.color(); } protected int radius() { return workerBall.radius(); } Decorated Ball protected int x() protected int y() { return workerBall.x(); } { return workerBall.y(); } protected Rectangle region() { return workerBall.region(); } protected void moveTo( int x, int y ) { workerBall.moveTo( x, y ); } protected void setMotion( double ndx, double ndy ) { workerBall.setMotion( ndx, ndy ); } protected double xMotion() { return workerBall.xMotion(); } protected double yMotion() { return workerBall.yMotion(); } } Decorated Ball public class ExpandingBall extends DecoratedBall { public ExpandingBall( MovableBall aBall ) { super( aBall ); } public void move () { super.move(); region().height = ( region().height * 11 ) / 10; region().width = ( region().width * 11 ) / 10; } } Decorated Ball public class DeceleratingBall extends DecoratedBall public DeceleratingBall( MovableBall aBall ) { super( aBall ); } public void move() { super.move(); setMotion( xMotion() * 0.95, yMotion() * 0.95 ); } } Chapter 12: Polymorphism • polymorphism comes from the Greek root for “many forms” • polymorphism is about how we can use different objects in the same place in our program, i.e., polymorphism depends on objects that are substitutable for one another • In object-oriented languages, polymorphism results from: – the is-a relationship of inheritance, – the mechanisms of message passing, and – concept of substitutability and polymorphic variables Polymorphic Variable • A polymorphic variable can hold many different types of values – Example: “PinBallTarget target” can be assigned a “Hole”, “ScorePad”, etc. • Object-oriented languages often restrict the types of values to being subclasses of the declared type of the variable. Varieties of Polymorphism • Pure polymorphism - a single function (code body) can operate on data of any type. Most • overriding • deferred methods / generics • overloading / ad hoc polymorphism – multiple functions (code bodies) with the same name each handle a different data type Least Pure Polymorphism • In dynamically-typed languages (e.g., Scheme) we can write one function that operate on data of any type: (define (sum-of-squares x y) (+ (square x) (square y) ) ) – neither the types of the formal parameters (x and y) or the result is known until run-time – sum-of-squares is not even limited to operating on numeric types – The only requires are that • the square operator knows how to handle x’s and y’s type • the + operator knows how to handle arguments of (square x)’s and (square y)’s types (In Java, that could be two Strings!) • Some OOP languages like Smalltalk are dynamically-typed and support pure polymorphism at the method level Overloading / Ad hoc Polymorphism • Multiple function bodies have the same name with each operating on different types of data • This common name is said to be overloaded • In strongly-typed language (i.e., Java), the compiler can often determine the appropriate function and generate only a single code sequence • Different forms of overloading exist – Overloading from separate classes: the same method name (or operator) is used by different classes that are not linked by inheritance (e.g, +, isEmpty()) – Parametric overloading: the same method name is used in the same class, but with different argument signatures Overloading from Separate Classes • All object-oriented languages permit the form of overloading • Resolution of the overloaded name by the compiler is easy by observing the class of the receiver, e.g., myVector.isEmpty() • Not bad programming style either if the name is meaningful in each class • The meaning might be complete different (i.e., dissimilar) in each class, e.g., – “draw” in a card class, and – “draw” in a circle class Parametric Overloading • the same method name is used in the same class, but with different argument signatures • Constructor methods often use parametric overloading, e.g., the Rectangle class Rectangle() Rectangle(int width, int height) Rectangle(int width, int height, int x, int y) Rectangle(Point origin) Rectangle(Dimension widthAndHeight) Rectangle(Point origin, Dimension widthAndHeight) • Any method (not just constructors) can be overloaded as long as each method has a distinct argument signature Overriding • The superclass has a general method, say doSomething(), but a subclass defines a method with the same name that hides access to the superclass’s method. • Two different forms of overriding: – replacement – code from the parent class is not executed at all – refinement – parent’s code is executed from the subclasses code by using “super.doSomething()” Number - Abstract Class Example • Parent class for numeric wrapper classes: Integer, Long, Double, etc. • Subclasses must override abstract methods public abstract class Number { public abstract int intValue(); public abstract long longValue(); public abstract float floatValue(); public abstract double doubleValue() public byte byteValue() {return (byte) intValue;} public short shortValue() { return (short) intValue(); } } // end Number Generic • Many languages are statically-typed, that is, they require us to declare the type of a variable in our code. Ada generics and C++ templates are constructs that provide polymorphism of this sort, in a statically-typed way. Java 5.0 (aka Java 1.5) supports generic classes, too! template <class Worker> public class Decorator { Worker myInstanceVariable; public Worker getValue() { return myInstanceVariable; } ... } • This allows me to create decorators for objects of any type: – Decorator<int> – Decorator<Ball> • This mechanism enables programmers to create nearly-pure polymorphism by declaring the kind of object that can be "wrapped". The template gives enough information that the compiler can verify that the polymorphic behavior will exist at run-time. Efficiency and Polymorphism • The use of polymorphism tends to optimize program development time and reliability by aiding in ability to reuse code • However, the trade-off is that at run-time the execution is slightly slower