Herencia es uno de los pilares en la Programacion Orientada a Objetos.
En esta diapositiva se muestra los principios de herencia y su implementacion en Java con clases abstractas e interfaces
1. Lenguajes de Programación 2
Programación Orientada a Objetos
Herencia
Ing. Gustavo Arsenio Sosa Cataldo
FACULTAD POLITÉCNICA - UNA
2. • Las clases solas no son suficientes para conseguir:
• Reutilización
• Generar código que:
• Capture los aspectos comunes en grupos de estructuras
similares, y
• Permita la variación de estructuras de datos y algoritmos
subyacentes
• Extensibilidad
• Necesidad de mecanismos para lograr:
• Principio Abierto-Cerrado
• Principio de la Elección Única
Introducción
3. Entre algunas clases pueden existir relaciones conceptuales:
Generalización: Se detectan las propiedades comunes.
Extensión: Se amplían las funcionalidades.
Especialización: Se implementan funcionalidades que son
especificas
Combinación: Se combinan las funcionalidades de dos o más
objetos
¿Tiene sentido crear una clase a partir de otra(s)?
Herencia: soporte para registrar y utilizar estas relaciones,
que posibilita la definición de una clase a partir de
otra(s).
Introducción
4. Jerarquía de Clases
La herencia permite organizar las clases en jerarquías en las
cuales se:
Reutiliza el código de los objetos Padres.
Extiende los tipos de objetos del sistema.
Puede existir una clase “raíz” en la jerarquía de la cual heredan
las demás directa o indirectamente.
La clase raíz incluye todas las características comunes a todas
las clases
En Java esta clase es la clase Object
• boolean equals(Object o)
• String toString()
• int hashCode()
6. Herencia entre clases
Si una clase B hereda de otra A, entonces:
B incorpora la estructura (atributos) y comportamiento (métodos) de A,
B puede incluir adaptaciones:
B puede añadir nuevos atributos y métodos
B puede redefinir métodos de A
• Refinamiento: Extendiendo el uso de un método de A
• Reemplazo: Sobrescribir la implementación de un método de A
B puede implementar un método abstracto en A
B hereda de A (A es la superclase y B la subclase)
C hereda de B y A
B y C son subclases de A
B es un descendiente directo de A
C es un descendiente indirecto de A
7. Tipos de Herencia
• Herencia simple
• Una clase puede heredar de una única
clase.
• Java, C#
• Herencia múltiple
• Una clase puede heredar de varias clases.
• Clases forman un grafo dirigido acíclico
• Problemas:
• Herencia Repetida.
• Conflicto de Nombres.
A
B C
D
B C
D
8. Problemas de la Herencia Múltiple
• Herencia Repetida
Ocurre cuando se hereda una misma
característica de dos o más líneas de
herencia.
• Solución
1.Especificar que línea de herencia usar.
2.Herencia Parcial, se elige que heredar
de cada línea de herencia.
3.Renombrar características heredadas
B
a, b
C
a, c
D
a, b, c, d
A
a
9. Problemas de la Herencia Múltiple
• Conflicto de Nombres
Ocurre cuando se heredan característica
diferentes pero con mismo nombre de dos
o más líneas de herencia.
• Solución
1.Especificar que línea de herencia usar.
2.Herencia Parcial, se elige que heredar
de cada línea de herencia.
3.Renombrar características heredadas
B
b, x
C
c, x
D
b, c, x
10. ¿Cómo detectar la herencia durante
el diseño?
• Generalización (Factorización)
Se detectan clases con un comportamiento común
(p.e. Libro y Revista son de tipos de Publicación)
• Especialización (Abstracción)
Se detecta que una clase es un caso especial de otra
(p.e. Rectángulo de Polígono)
11. Polígonos y Rectángulos
Tenemos la clase Poligono y necesitamos representar
rectángulos:
¿Debemos crear la clase Rectángulo partiendo de cero?
Podemos aprovechar la existencia de similitudes y
particularidades entre ambas clases
Polígono
vértices : List<Punto>
trasladar(int a, int b)
dibujar()
borrar()
perimetro()
Polígono(List<Punto> v)
Rectángulo
lado1 : int
lado2 : int
perimetro()
Rectángulo(List<Punto> v, int l1, int l2)
diagonal()
12. Polígonos y Rectángulos
Un rectángulo tiene muchas de las características de un polígono
(dibujar(), borrar(), trasladar())
Pero tiene características especiales (diagonal(), lado1, lado2)
Algunas características de polígono pueden implementarse más
eficientemente (perímetro())
Polígono
vértices : List<Punto>
trasladar(int a, int b)
dibujar()
borrar()
perimetro()
Polígono(List<Punto> v)
Rectángulo
lado1 : int
lado2 : int
perimetro()
Rectángulo(Punto vsi, int l1, int l2)
diagonal()
13. import gráficos.Punto;
Import java.util.List;
public class Polígono {
//Un polígono es una lista de puntos
protected List<Punto> vértices = null;
public Polígono(List<Punto> vértices) {
this.vértices = vértices;
}
public void trasladar (double a, double b) {…}
public void dibujar() {…}
public void borrar() {…}
public double perímetro() {…}
}
Polígonos y Rectángulos
14. public double perímetro() {
double total = 0;
Punto ant = null;
Punto actual = vertices.get(0);
for (int i = 1; i < vertices.size(); i++){
ant = actual;
actual = vertices.get(i);
total = total + actual.distancia(ant);
}
total = total +
actual.distancia(vertices.get(0));
return total;
}
Polígonos y Rectángulos
15. public class Rectángulo extends Polígono {
protected double lado1, lado2; //Nuevos atributos
public Rectángulo(Punto vsi; double lado1,
double lado2) {
this.vértices = new List<Punto>;
this.vértices.add(vsi);
Punto vsd = new Punto (vsi)
vsd.trasladar (0, lado1);
this.vertices.add(vsd);
...
this.lado1 = lado1;
this.lado2 = lado2;
}
...
Polígonos y Rectángulos
16. public double perímetro() {
return (2*(lado1 + lado2 ));
}
public double diagonal() {
return Math.sqrt(Math.pow(lado1, 2) +
Math.pow(lado2, 2))
}
// ¿Y que pasa con los demás métodos ?
}
Todas las demás características de Polígono están
disponibles automáticamente para la clase Rectángulo, no
es necesario que se repitan.
Polígonos y Rectángulos
17. Significado de la herencia
Clases Herencia
Módulo Mecanismo de Extensión Mecanismo de Reutilización
Tipo Mecanismo de Especialización Clasificador de Tipos
Sean:
• Prop(X): Conjunto de características de la clase X
• Dom(X): Conjunto de instancias de la clase X
A {Prop(A)}
B {Prop(B)}
• B Hereda de A Prop(A) Prop(B)
• Cualquier objeto de B puede ser
considerado un objeto de A
• Dom(B) Dom(A) B es un Subtipo de A
• Si se espera un objeto A, podemos recibir o
enviar un objeto B.
18. Significado de la herencia
Polígono
vértices : List<Punto>
trasladar(int a, int b)
dibujar()
borrar()
perimetro()
Polígono(List<Punto> v)
Rectángulo
lado1 : int
lado2 : int
perimetro()
Rectángulo(Punto vsi, int l1, int l2)
diagonal()
1. Prop(Polígono) = {vértices, trasladar(), dibujar(), borrar(), perímetro()}
2. Prop(Rectángulo) = {vértices, trasladar(), dibujar(), borrar(), perímetro(),
lado1, lado2, diagonal()}
19. Significado de la herencia
1. Dom(Polígono) = {recA, recB, polA, polB}
2. Dom(Rectángulo) = {recA, recB, PolB}
Rectángulo recA = new Rectángulo(…);
Polígono polA = new Polígono(…);
Polígono polB = new Rectángulo(…);
Rectángulo recB = new Rectángulo(…);
Polígono polC = null;
Rectangulo recC = null;
20. Significado de los subtipos
• El principio de sustitución de Liskov [B. Liskov 88]:
• “ Si para cada objeto O1 de tipo S hay un objeto O2 de tipo T, tal
que para todos los programas P definidos en términos de T, sí el
comportamiento de P no varía cuando se sustituye O2 por O1
entonces S es un subtipo de T ”
• Funciones que utilizan referencias a superclases deben ser capaces
de utilizar objetos de sus subclases sin saberlo.
• public static void dibujarEnPantalla(Polígono p);
• dibujarEnPantalla(new Rectangulo(...))
21. Herencia y Creación
Los constructores no se heredan
El constructor de la clase hija refina el comportamiento del
constructor del padre
La primera sentencia del constructor de la clase hija SIEMPRE es
una llamada al constructor de la clase padre.
La llamada al constructor del padre puede ser:
Implícita:
• Si se omite, se llamará implícitamente al constructor
por defecto de la clase padre
• Equivale a poner como primera sentencia super();
Explícita:
• super(); o super(a,b); o . . .
• Dependiendo del número y tipo de parámetros se invoca
uno de los constructores de la clase padre
22. Acceso protegido en Java
• Una subclase no puede acceder a los atributos o métodos privados de su
superclase
• Para permitir que un método de la subclase pueda acceder a un atributo o
un método de la superclase, éste tiene que declararse como protected o
public
• Resumen de modificadores de acceso:
– private – visible sólo en la clase
– public – visible a todas las clases
– protected – visible a las subclases y a (sub)clases del paquete
– default – visible en las clases del paquete
23. Herencia en Java
• Toda clase hereda directa o indirectamente de la clase Object
• public class Poligono {...} // hereda de Object
• public class Rectangulo extends Poligono {...}
• Una subclase hereda de su superclase métodos y atributos
tanto de clase como de instancia, pero solo puede acceder a las
que están definidas como public o protected.
• Una subclase puede añadir nuevos métodos y atributos.
• Una subclase puede redefinir métodos heredados.
24. Redefinición
• La redefinición reconcilia la Reutilización con la Extensibilidad:
• “Es raro reutilizar un componente software sin necesidad de
cambios”
• Los atributos no se pueden redefinir, sólo se OCULTAN
• El campo de la superclase todavía existe pero solo se puede
acceder por medio de super
• Un método de la subclase con la misma signatura y valor de
retorno que un método de la superclase lo está REDEFINIENDO.
• Si se cambia el tipo de los parámetros se está SOBRECARGANDO
el método original y no redefiniendo
25. Redefinición de métodos
• Una clase hija puede redefinir un método de la clase padre por
dos motivos:
• Reemplazo:
• Mejorar implementación.
• Ej: redefinición de perímetro() en la clase
Rectángulo.
• Cambiar la Implementación sin variar la semantica.
• Refinamiento:
• Método del padre + acciones específicas.
• La invocación al método del padre se hace usando la
palabra super
26. Refinamiento. Ejemplo
public class CuentaAhorro extends Cuenta {
...
public void ingresar(double cantidad) {
//Hace lo mismo que el método de la clase padre
super.ingresar(cantidad);
//Además hace cosas propias de la CuentaAhorro
beneficio = cantidad * PORCENTAJE_BENEFICIO;
}
}
27. ¿Qué se puede cambiar en la
redefinición?
• El nivel de acceso
• Siempre que se relaje
• Puede pasar de protected a public
• Por ejemplo, método clone en Object es protected
• No se puede pasar de public a private
• El tipo de retorno
• Siempre que el tipo de retorno del método redefinido sea compatible
con el tipo de retorno del método original.
• Object protected Object clone() … (desde Java 1.5)
• Punto public Punto clone() …
28. Restringir la herencia y
redefinición
En Java se puede aplicar el modificador final a un
método para indicar que no puede ser redefinido.
El modificador final es aplicable a una clase
indicando que no se puede heredar de ella.
¿El modificador final va contra el principio abierto-
cerrado?
29. Polimorfismo
• El término polimorfismo significa que hay un nombre (referencia,
método o clase) y muchos significados diferentes para el mismo
(distintas definiciones).
• Formas de polimorfismo [Budd’02]:
– Polimorfismo de asignación (variables polimorfas)
– Polimorfismo puro (función polimorfa)
– Polimorfismo ad hoc (sobrecarga)
– Polimorfismo de inclusión (redefinición)
– Polimorfismo paramétrico (genericidad)
30. Polimorfismo de Asignación
Capacidad de una entidad de referenciar en tiempo de ejecución
a instancias de diferentes clases
El conjunto de clases a la que se puede hacer referencia está
restringido por la Herencia.
Dada una referencia R de tipo T, en un lenguaje orientado a
objetos fuertemente tipado R puede referenciar a cualquier objeto
de tipo S, siempre que S sea un subtipo de T.
Number n;
n = new Integer();
n = new Double();
n = new BigDecimal();
31. Tipo estático y tipo dinámico
• Tipo estático (te):
– Tipo asociado en la declaración. Ej: Number n;
• Tipo dinámico:
– Tipo correspondiente a la clase del objeto conectado a la
entidad en tiempo de ejecución. Ej: n = new Float(3.14);
• Conjunto de tipos dinámicos (ctd):
– Conjunto de posibles tipos dinámicos de una entidad
A oa; B ob; C oc;
te(oa) = A ctd(oa) = {A,B,C,D,E,F}
te(ob) = B ctd(ob) = {B, D, E}
te(oc) = C ctd(oc) = {C,F}
32. Entidades y rutinas polimorfas
Conexión polimorfa: el origen y el destino tiene tipos diferentes
Poligono p;
Rectangulo r;
a) asignación:
p = r;
-- p es una entidad polimorfa
(polimorfismo de asignación)
b) paso de parámetros:
void f (Poligono p)… -- f es una rutina polimorfa
(polimorfismo puro)
33. Polimorfismo puro vs. Sobrecarga
• Funciones sobrecargadas ≠ funciones polimórficas
• Sobrecarga:
– Dos o mas funciones comparten el nombre y distintos
argumentos (nº y tipo). El nombre es polimórfico.
– Distintas definiciones (distintos comportamientos)
– Función correcta se determina en tiempo de compilación
según la signatura.
• Funciones polimórficas:
– Una única función que puede recibir una variedad de
argumentos (comportamiento uniforme).
– La ejecución correcta se determina dinámicamente en
tiempo de ejecución.
34. Herencia y sistema de tipos
A a; B b; C c; D d;
¿Son válidas las siguientes asignaciones?
a = b; c = b; a = d
35. Ligadura dinámica ó
Enlace dinámico
{fδ}
redefine f
¿qué versión de f se
ejecuta?
A oa;
… // asignacion
de oa
oa.f(..);
Regla de la ligadura dinámica
La forma dinámica del objeto determina la versión de la operación que
se aplicará.
36. • La versión de un método en una clase es la introducida
por la clase (redefinición u original) o es la heredada.
• Ejemplo:
Poligono p = new Poligono();
Rectangulo r = new Rectangulo();
Double x;
x = p.perimetro() → perimetro POLIGONO
x = r.perimetro() → perimetro RECTANGULO
p = r;
x = p.perimetro() → perimetro RECTANGULO
Ligadura dinámica ó
Enlace dinámico
37. {fδ}
redefine f
A a;
B b = new B();
D d = new D();
a = b;
a.f(); //q versión?
a = d
a.f(); //q versión?
Ligadura dinámica ó
Enlace dinámico
38. Ejemplo 2:
void visualizar (Figura [] figuras){
for (Figura figura : figuras)
figura.dibujar();
}
¿Qué sucede si aparece un nuevo tipo de figura?
¿Qué relación existe entre ligadura dinámica y comprobación
estática de tipos?
Sea el mensaje x.f (), la comprobación estática de tipos garantiza que al
menos el mensaje sea válido, y la ligadura dinámica garantiza que se
ejecutará la versión más apropiada.
Ligadura dinámica ó
Enlace dinámico
39. Ejemplo ligadura dinámica, super y this
class Uno {
public int test(){return 1;}
public int result1(){return this.test();}
}
class Dos extends Uno{
public int test(){return 2;}
}
class Tres extends Dos{
public int result2(){return this.result1();}
public int result3(){return super.test();}
}
class Cuatro extends Tres{
public int test(){return 4;}
}
40. public class PruebaSuperThis{
public static void main (String args[]){
Uno ob1 = new Uno();
Dos ob2 = new Dos();
Tres ob3 = new Tres();
Cuatro ob4 = new Cuatro();
System.out.println("ob1.test = "+ ob1.test());
System.out.println("ob1.result1 = " + ob1.result1());
System.out.println("ob2.test = " + ob2.test());
System.out.println("ob2.result1 = " + ob2.result1());
System.out.println("ob3.test = " + ob3.test());
System.out.println("ob4.result1 = " + ob4.result1());
System.out.println("ob3.result2 = " + ob3.result2());
System.out.println("ob4.result2 = " + ob4.result2());
System.out.println("ob3.result3 = " + ob3.result3());
System.out.println("ob4.result3 = " + ob4.result3());
}
}
Ejemplo ligadura dinámica, super y this
1
41. {fδ}
redefine f
A a;
B b = new B();
D d = new D();
a = b;
a.f(); //versión B
a = d
a.f(); //versión D
Principio de la Elección Única
Principio de la Elección Única
Gracias al polimorfismo el modulo A conoce todas sus variantes por
medio del enlace dinámico se aplica la versión correcta de una operación
42. Código Genérico
Un único código con diferentes interpretaciones en tiempo
de ejecución
Es fundamental que el lenguaje soporte:
Polimorfismo
Ligadura Dinámica
El mismo código ejecutará cosas distintas en función del
Tipo Dinámico de la entidad polimórfica (ligadura dinámica)
Gracias al polimorfismo y la ligadura dinámica se satisface
el criterio de reutilización de Variación de la
Implementación.
43. Código Genérico
class CalculadorDeCostos {
/* Los objetos de esta clase calculan el costo de
diversas cosas */
...
public double precioDeVallado(Parcela p) {
Poligono forma = p.getForma();
double costo = forma.getPerimetro() *
this.getCostoVallado();
return costo;
}
}
forma puede ser cualquier objeto de tipo Poligono.
El mensaje forma.getPerimetro() tendrá diferentes significados según
sea el tipo dinámico de forma.
44. Copias de Objetos
Tipos de copia:
Copia superficial: los campos de la copia
son exactamente iguales a los del objeto
original.
Copia profunda: los campos primitivos de
la copia son iguales y las referencias son
copias de los objetos referenciados por el
original.
Adaptada: adaptada a la necesidad de la
aplicación.
45. Copia superficial
Alias Dinámico:
Incorrecto al
compartir las
últimas
operaciones
No deberían
tener el mismo
valor de código
46. Copia profunda
No tiene
sentido
duplicar el
objeto Persona
No deberían
tener el mismo
código
48. Copia adaptada
Para implementar la copia se debe redefinir el método:
protected Object clone();
class Cuenta {
...
public Cuenta clone() {
Cuenta clon = super.clone(); // copia superficial
clon.codigo = Cuenta.getSgteCodigo(); // código nuevo
clon.ultOper = new ArrayList<Integer>();
// se copian las operaciones
for (Integer oper : this.ultOper) {
clon.ultOper.add(new Integer(oper));
}
return clon;
}
}
49. Igualdad de Objetos
Tipos de igualdad:
Superficial: los campos primitivos de los dos objetos son iguales
y las referencias apuntan a los mismos objetos (==).
Profunda: los campos primitivos son iguales y las referencias no
son los mismos objetos pero estos son iguales en profundidad
(equals).
Adaptada: adaptada a las necesidades de la aplicación.
¿Cuándo dos cuentas son iguales?
50. Igualdad de Objetos
Para implementar la comparación se debe redefinir el método:
public boolean equals(Object o2);
class Cuenta {
...
public boolean equals(Object o2) {
if(!(o2 instanceof Cuenta) ) return false;
Cuenta c2 = (Cuenta) o2;
if ( this.saldo != c2.saldo || this.titular != c2.titular ||
this.ultOper.size() != c2.ultOper.size() )
return false;
for (int i = 0; i < this.ultOper.size() ; i++) {
if (! this.ultOper.get(i).equals(
c2.ultOper.get(i)) )
return false;
}
return true;
}
}
51. Genericidad restringida
Public class Vector <T> {
private int count;
public T item( int i ){…}
public void put (T v, int index){…}
public Vector<T> suma (Vector<T> otro){
Vector<T> result= new Vector<T>();
for(int i = 1; i <= count; i++) {
result.put( this.item(i) + otro.item(i) , i);
}
return result;
}
}
52. Genericidad restringida
Public class Vector <T extends Number> {
private int count;
public T item( int i ){…}
public void put (T v, int index){…}
public Vector<T> suma (Vector<T> otro){
Vector<T> result = new Vector<T>();
for(int i = 1; i <= count; i++) {
result.put( this.item(i) + otro.item(i) , i);
}
return result;
}
}
53. Herencia de una clase Genérica
La subclase puede seguir siendo genérica:
Class Pila<T>
extends ArrayList<T> {…}
Al heredar de una clase genérica se puede restringir el tipo:
class ListaOrdenada<T extends Comparable>
extends LinkedList<T> {…}
Al heredar de una clase genérica se puede instanciar el tipo:
Class CajaSeguridad
extends LinkedList<Valorable> {…}
54. Genericidad y Herencia
1. List<Poligono> lp;
2. List<Rectangulo> lr = new List<Rectangulo>();
3. lp = lr; //Error de compilación
55. Tipos Comodín
Dado el código de la clase Paint:
Class Paint {
public static void imprimir (List<Poligono> poligonos) {
for(Poligono p : poligonos)
System.out.println(p);
}
}
El siguiente código daría error:
List<Rectangulo> lr = new LinkedList <Rectangulo> ();
Paint.imprimir(lr); //Error no es una List<Poligono>
Para que no de error hay que usar el tipo comodín en la declaración del
método
void imprimir (List<? extends Poligono> poligonos)
56. Dado el siguiente código:
Figura f; Rectangulo p;
p = new Rectangulo(...);
f = p;
f.dibujar();
¿Como se implementa el método dibujar en la clase Figura?
Clases Abstractas
57. Clases Abstractas
public abstract class Figura {
public abstract double perimetro();
public abstract void dibujar();
public abstract void borrar();
public abstract void mover();
public abstract void rotar();
…
}
public abstract class FiguraCerrada
extends Figura {
public abstract double area();
}
public abstract class Poligono
extends FiguraCerrada {
ArrayList<Punto> vertices;
public double perimetro() {...}
public void dibujar() {...}
public void borrar() {...}
public void mover() {...}
public void rotar() {...}
}
public class Rectangulo extends Poligono {
double largo, ancho;
public double area() {...}
public double perimetro {...}
public double diagonal() {...}
}
Figura
+perimetro():double
+dibujar(): void
+borrar(): void
+mover(): void
+rotar():void
FiguraCerrada
Polígono Elipse
Rectángulo Circulo
Rombo
FiguraAbierta
58. Clases Abstractas
Toda clase que contenga algún método abstracto (heredado o no) es
abstracta.
Una clase puede ser abstracta y no contener ningún método abstracto.
Especifica una funcionalidad que es común a sus subclases.
Puede ser total o parcialmente abstracta.
No es posible crear instancias de una clase abstracta, pero si
declarar referencias del tipo de la clase.
La clase puede incluir la definición del constructor.
Las clases abstractas sólo tienen sentido en un lenguaje con
comprobación estática de tipos.
59. Clases Parcialmente Abstractas
Contienen métodos abstractos y efectivos.
Los métodos efectivos pueden hacer uso de los abstractos.
Importante mecanismo para incluir código genérico.
Incluyen comportamiento abstracto común a todos los descendientes.
“programming with holes” - Programación con hoyos
Capturar lo conocido sobre el comportamiento y la estructura
de datos que caracterizan a cierta área de aplicación, dejando
una puerta abierta a la variación
Factorización del comportamiento común
61. Interfaces
Son similares a “clases totalmente abstractas” que solo
declaran el comportamiento para un objeto pero no lo
implementan
Se declaran utilizando la palabra interface.
public interface Comparable <T> {
public int compararCon(T o2);
}
Por defectos todos sus métodos son públicos y abstractos.
Sus atributos solo pueden ser públicos, constantes y de clase.
public static final int ATRIBUTO = 1;
62. Interfaces
Las clases pueden implementar un interfaz
class Entero implements Comparable<Numero> {
...
Public int compararCon (Numero o2) {
return this.valorEntero() – o2.valorEntero();
...
}
Cualquier clase efectiva que implemente una interfase debe definir todos
los métodos de dicho interfase
Si la clase no proporciona la implementación para todos los métodos del
interfase debe ser declarada como abstracta
No se pueden crear objetos de una Interfaz, pero si puede ser utilizada como tipo
de dato.
Comparable<Numero> c = new Entero();
63. Interfaces Parametrización del
Comportamiento
...
Colección <Cuenta> cuentas = Banco.getCuentas();
if (cuentas.buscarCuentasSaldoCero(cuentas)) {
System.out.println(“Hay cuentas con saldo cero”)
}
if (cuentas.buscarCuentasSaldoNegativo(cuentas)) {
System.out.println(“Hay cuentas con saldo negativo”)
}
...
67. Interfaces Parametrización del
Comportamiento
public interface ICondicion<T> {
public boolean test ( T obj );
}
public class CuentaSaldoCero implements ICondicion<Cuenta> {
public boolean test ( Cuenta obj ) {
if (obj.getSaldo() == 0.0) {
return true;
}
return false;
}
}
public class CuentaSaldoNegativo implements ICondicion<Cuenta> {
public boolean test ( Cuenta obj ) {
if (obj.getSaldo() < 0.0) {
return true;
}
return false;
}
}
68. Interfaces Parametrización del
Comportamiento
...
Colección <Cuenta> cuentas = Banco.getCuentas();
if (cuentas.buscar (new CuentaSaldoCero())) {
System.out.println(“Hay cuentas con saldo cero”);
}
if (cuentas.buscar (new CuentaSaldoNegativo())) {
System.out.println(“Hay cuentas con saldo negativo”);
}
...
69. Clases Anónimas
• A veces no es necesario usar la clase más de una vez!
Colección <Cuenta> cuentas = Banco.getCuentas();
// buscar cuentas con saldo mayor a 10.000
if (cuentas.buscar (new ICondicion<Cuenta> (){
public boolean test (Cuenta obj) {
return obj.getSaldo > 10000.0;
}
}
) {
System.out.println(“Hay cuentas con saldo mayor a
10.000”);
}
...
70. Herencia de Interfaces
Una interfaz puede ser extendida para definir más funcionalidades
necesarias en otros objetos.
public interface Nombrable {
public void setNombre();
public String getNombre();
}
public interface NombrableGraficamente extends Nombrable {
public void graficarNombre();
}
71. Implementación de múltiples
Interfaces
Una clase puede implementar más de una interfaz
public interface Nombrable {
public void setNombre(String n);
public String getNombre();
}
public class BienActivoFijo implements Nombrable, Codificable
{
...
}
public interface Codificable {
public void setCodigo(Integer n);
public Integer getCodigo();
}
72. Herencia Múltiple
La herencia múltiple permite:
Extender el sistema de tipos, permitiendo que la clase
heredada sea compatible con los tipos de las clases de cuales
hereda.
Reutilizar el código de dos o más clases en la clase hija
En Java no existe la Herencia Múltiple, sin embargo
puede ser esta puede ser emulada a través del uso de
las interfaces
73. Herencia Múltiple
Supóngase que un sistema académico posee las clases Alumno y
Profesor de las cuales se desea extender un nuevo objeto llamado
AlumnoAsistente
En un sistema OO con herencia múltiple la solución sería la siguiente:
Alumno
private String nombre
private String cedula
private Asignatura materias[]
public Alumno(String n, String c, Asignatura m[])
public String getNombre()
public String getCedula()
public Asignatura[] getMaterias()
public void estudiar ()
public void irAClases()
public void rendir()
Profesor
private String nombre
private String cedula
private Asignatura asignaturas[]
public Profesor(String n, String c, Asignatura a[])
public String getNombre()
public String getCedula()
public Asignatura[] getAsignaturas()
public void preprarClases()
public void darClases()
public void tomarExamen()
AlumnoAsistente
74. Herencia Múltiple
En Java, un sistema OO sin herencia múltiple, la solución consiste en
heredar de una de las clases e implementar una interfaz que defina el
comportamiento de la otra clase
Alumno
private String nombre
private String cedula
private Asignatura materias[]
public Alumno(String n, String c, Asignatura m[])
public String getNombre()
public String getCedula()
public Asignatura[] getMaterias()
public void estudiar ()
public void irAClases()
public void rendir()
Profesor
public String getNombre()
public String getCedula()
public Asignatura[] getAsignaturas()
public void preprarClases()
public void darClases()
public void tomarExamen()
AlumnoAsistente
75. Herencia Múltiple
Sin embargo esta solución es parcial con respecto a la herencia múltiple:
Se extiende el sistema de tipos pues AlumnoAsistente hereda el
comportamiento de Alumno e implementa el comportamiento definido por la
interface Profesor .
Sin embargo la reutilización es parcial ya que AlumnoAsistente debe
repetir código de los métodos de Profesor.
Alumno
private String nombre
private String cedula
private Asignatura materias[]
public Alumno(String n, String c, Asignatura m[])
public String getNombre()
public String getCedula()
public Asignatura[] getMaterias()
public void estudiar ()
public void irAClases()
public void rendir()
Profesor
public String getNombre()
public String getCedula()
public Asignatura[] getAsignaturas()
public void preprarClases()
public void darClases()
public void tomarExamen()
AlumnoAsistente
76. Herencia Múltiple
Los métodos con el mismo nombre en Alumno e Profesor no entran en
conflicto pues para ambos casos getNombre y getCedula se refieren al
mismo dato
Alumno
private String nombre
private String cedula
private Asignatura materias[]
public Alumno(String n, String c, Asignatura m[])
public String getNombre()
public String getCedula()
public Asignatura[] getMaterias()
public void estudiar ()
public void irAClases()
public void rendir()
Profesor
public String getNombre()
public String getCedula()
public Asignatura[] getAsignaturas()
public void preprarClases()
public void darClases()
public void tomarExamen()
AlumnoAsistente
77. Herencia Múltiple
Una solución equivalente a la Herencia Múltiple sería que los objetos de la
clase AlumnoAsistente deleguen la implementación de los métodos de la
interface Profesor en un objeto de alguna clase que los implementen
Para ello, los objetos de la clase AlumnoAsistente deben componerse de tal
objeto.
Alumno
private String nombre
private String cedula
private Asignatura materias[]
public Alumno(String n, String c, Asignatura m[])
public String getNombre()
public String getCedula()
public Asignatura[] getMaterias()
public void estudiar ()
public void irAClases()
public void rendir()
Profesor
public String getNombre()
public String getCedula()
public Asignatura[] getAsignaturas()
public void preprarClases()
public void darClases()
public void tomarExamen()
AlumnoAsistente
ObjetoQue
Implementa
Profesor
78. Herencia Múltiple
Por ejemplo si se tiene una clase ImplProfesor que implementa el
comportamiento de la interface Profesor, los objetos de la clase
AlumnoAsistente pueden componerse de un objeto de la clase
ImplProfesor sobre el cual delegar los comportamientos definidos por la
interface Profesor.
Alumno
private String nombre
private String cedula
private Asignatura materias[]
public Alumno(String n, String c, Asignatura m[])
public String getNombre()
public String getCedula()
public Asignatura[] getMaterias()
public void estudiar ()
public void irAClases()
public void rendir()
Profesor
public String getNombre()
public String getCedula()
public Asignatura[] getAsignaturas()
public void preprarClases()
public void darClases()
public void tomarExamen()
AlumnoAsistente
ObjetoQue
Implementa
Profesor
ImplProfesor
private String nombre
private String cedula
private Asignatura asignaturas[]
public String getNombre()
public String getCedula()
public Asignatura[] getAsignaturas()
public void preprarClases()
public void darClases()
public void tomarExamen()
79. Herencia Múltiple
1. class AlumnoAsistente extends Alumno implements Profesor {
2. private Profesor p; // referencia al objeto que implementa Profesor
3. public AlumnoAsistente(String nom, String ced, Asignatura[] matAlu, Asignatura[] matProf) {
4. super(nom, ced, matAlu);
5. this.p = new ProfesorImpl(nom, ced, matProf);
6. }
7. // métodos delegados en el objeto que implementa Profesor
8. public Asignatura[] getAsignaturas() { return p.getAsignaturas() }
9. public void enseñar() { p.enseñar () }
10. public void prepararClases() { return p.prepararClase() }
11. public void tomarExamen() { return p.tomarExamen() }
12.
13. // los métodos heredados de Alumno complementan el comportamiento del tipo Alumno
14. // y también complementan la implementación de la interfaz Profesor
15. }
80. Herencia Múltiple
El siguiente código es válido:
1. AlumnoAsistente alAs = new AlumnoAsistente(n, c, matAl, matPr);
2. // el objeto es de tipo Alumno por heredar de dicha clase
3. Alumno a = alAs;
4. // el objeto es de tipo Profesor por implementar dicha interfaz
5. Profesor p = alAs;