Por ejemplo, todos los glyphs tienen operaciones comunes como getX, getY y moveTo. Además, desde el punto de vista de representación, todos tienen un punto de referencia. Estas operaciones se definen normalmente en la clase:
en la clase:
Los métodos getX, getY y moveTo son los métodos que se usaron la
clase pasada. Son métodos definidos para el usuario de esta biblioteca
de clases. En cambio el método draw nunca será usado por el usuario
de la biblioteca. Este método se coloca en la clase Glyph para poder
implementar la clase Animator. Esta clase mantiene un arreglo con todos
los glyphs puestos en la ventana. Cuando llega el momento de dibujar
todos estos glyphs, basta ejecutar el siguiente código:
class Glyph extends Program {
int x, y; // el punto de referencia
// las operaciones comunes a todos los glyphs
int getX() {
return x;
}
int getY() {
return y;
}
void moveTo(int x, int y) {
this.x= x;
this.y= y;
}
void draw(Pizarra p) {
}
}
en donde glyphs es el arreglo de objetos de la clase Glyph y
p es un objeto de la clase Pizarra (representa la ventana).
int i= 0;
while (i<numGlyphs) {
glyphs[i].draw(p);
i= i+1;
}
Es importante destacar que el usuario utilizará finalmente las subclases de Glyph, es decir Box, Ellipse y Text, y no Glyph propiamente tal. Sin embargo, es útil definir la clase Glyph, porque es el factor común que permite simplificar el uso y la definición de las subclases. El programador de las subclases usará Glyph como un molde, preocupándose solamente de los aspectos específicos de las subclases.
Explicaciones:
class Box extends Glyph {
int w; // nuevas variables de instancia
int h;
// el constructor
Box(int x, int y, int w, int h) {
this.x= x;
this.y= y;
this.w= w;
this.h= h;
}
// redefinición de métodos
void draw(Pizarra p) {
p.drawRect(x, y, x+w, y+w);
}
// nuevos métodos
void setDim(int w, int h) {
this.w= w;
this.h= h;
}
}
En Java todos los objetos pertenecen a la clase Object.
Una subclase hereda de su clase base:
Como la clase base ha heredado las variables de instancia y métodos de su propia clase base, entonces la subclase también las hereda. Es decir, la herencia también es transitiva.
Por ejemplo, la clase Program define los métodos println, readLine, readInt, etc. Estos métodos son heredados por la clase Glyph y por lo tanto por la clase Box.
Observación importante: la subclase no hereda los constructores.
Los métodos redefinidos se distinguen de la definición
de nuevos métodos porque poseen el mismo nombre, número y
tipo de paramétros que un método de la clase base (que eventualmente
fue heredado de otra clase).
void draw(Pizarra p) {
p.drawRect(x, y, x+w, y+w);
}
Enlace dinámico
En el siguiente código:
¿Qué método se invoca? ¿El que se definió en la clase Glyph?
¿El que se definió en la clase Box?
Pizarra p= ...;
Glyph gl= new Box(100, 200, 20, 30);
...
gl.draw(p);
La respuesta es que se invoca el de la clase Box.
En el código que dibuja todos los glyphs del animator:
Los glyphs pertenecerán a distintas subclases: Box, Ellipse y Text.
Este código invoca el método que se ha redefinido en cada una de estas
subclases. En realidad el método draw definido en la clase Glyph
nunca será invocado porque no existirán objetos que sean exactamente
de la clase Glyph.
int i= 0;
while (i<numGlyphs) {
glyphs[i].draw(p);
i= i+1;
}
Aún así es necesario declarar el método draw en la clase Glyph para indicar que es un método común a todas las subclases.
La desventaja es que estos métodos no pueden ser invocados
a partir de variables que sean de tipo Glyph:
void setDim(int w, int h) {
this.w= w;
this.h= h;
}
Box box= new Box( ... );
Glyph gl= new Box( ... );
...
box.setDim( ... ); // Ok
gl.setDim( ... ); // error!