Tema 5.- Herencia

Anuncio
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
Tema 5.- Herencia
1.
2.
Herencia múltiple en C++: ambigüedad de nombres.........................................................2
Herencia en SMALLTALK ...............................................................................................4
2.1.
Determinación de los métodos a ejecutar: self y super..............................................4
2.2.
Herencia de métodos y variables de instancia ...........................................................5
2.3.
Herencia de métodos de clase ....................................................................................6
3. Herencia en JAVA ...........................................................................................................12
3.1.
Herencia de interfaces..............................................................................................12
1
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
1. Herencia múltiple en C++: ambigüedad de nombres
Una clase hereda métodos y atributos de más de una clase.
class Mamifero {
public:
int tiempo_incubacion;
char* habitat;
void comer(char*);
}
class Oviparo {
public:
int tamaño_huevos;
int habitat;
void comer(char*);
}
class Hominido: public Mamifero {
public:
int altura;
}
class Ornitorrinco: public Mamifero, public Oviparo {
void comer (char* c) {
// this.comer(c) es ambigüo y no puede escribirse aquí
this.Mamifero::comer(c)
//deshace la ambigüedad
}
Ambigüedad o conflictos de nombres en herencia de métodos: Redefinición del método
ambigüo, referenciando al que se desea heredar.
2
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
class A {
public:
void virtual mostrar (int i)
{.......}
void virtual ver (int p)
{....}
}
class B {
public:
void virtual mostrar (float f)
{.......}
void virtual ver (int n)
{....}
}
class C: public B, public A {
public:
void virtual mostrar (int i)
{A::mostrar(i);}
void virtual mostrar (float f)
{B::mostrar(f);}
void virtual verA (int p)
{A::ver(p);}
void virtual verB (int p)
{B::ver(p);}
}
main() {
C c;
c.mostrar(4);
c.mostrar(2.8);
}
3
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
2. Herencia en SMALLTALK
2.1.
Determinación de los métodos a ejecutar: self y super.
Clase Uno
prueba
^1
resultado1
^ self prueba
Clase Dos hereda de Uno
prueba
^2
Clase Tres hereda de Dos
resultado2
^ self resultado1
resultado3
^ super prueba
Clase Cuatro hereda de Tres
prueba
^4
ejemplo1 := Uno new.
ejemplo2 := Dos new.
ejemplo3:= Tres new.
ejemplo4 .= Cuatro new.
ejemplo1 prueba.
ejemplo1 resultado1
ejemplo2 prueba
ejemplo2 resultado1
ejemplo3 prueba
ejemplo4 resultado1
ejemplo3 resultado2
ejemplo4 resultado2
ejemplo3 resultado3
ejemplo4 resultado3
4
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
2.2.
Herencia de métodos y variables de instancia
La responsabilidad de los métodos de instancia es de la clase, es decir, cuando un objeto
recibe un mensaje será su clase quien los ejecute. Por ejemplo,
#(1 2 3) at:1 put:2
es un mensaje a un objeto de la clase Array. Cuando el objeto recibe el mensaje transfiere la
responsabilidad de su ejecución a la clase. La figura 1 muestra la composición de la clase
Carta (el objeto Carta). La clase contiene un diccionario con los métodos de instancia válidos
para esa clase. Contiene, además, los nombres de las variables de instancia con nombre.
Figura 1.- Composición de la clase Carta y un objeto de la clase Carta. Cada ventana indica
en su título la clase a la que pertenece el objeto que se inspecciona.
5
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
La herencia de métodos y variables de instancia sigue la jerarquía de clases típica de
Smalltalk.
Este es un resumen muy simplificado de ella.
Object
Behavior
Class
Metaclass
Collection
Set
Dictionary
SequenceableCollection
ArrayedCollection
Array
List
OrderedCollection
CharacterArray
String
ByteString
Magnitude
Number
Integer
Fraction
Character
Time
2.3.
Herencia de métodos de clase
En las primeras versiones de Smalltalk todas las clases eran objetos (instancias) de una
única clase, la clase Metaclass. Algo similar ocurre en JAVA. A nivel práctico esto implicaba
que la clase Metaclass era responsable de responder al método new para crear objetos. De
este modo era imposible redefinir el método new para cada clase.
A partir de Smalltalk-80 se amplia el concepto de metaclase de forma que cada clase
tenga la suya propia. Los métodos de clase, de los cuales el más típico es el método new, son
entonces responsabilidad de la metaclase, es decir, la clase de la cual es instancia una clase.
Cada clase tiene su correspondiente metaclase que se denomina con el nombre de la clase
seguido del mensaje class . Por ejemplo, la metaclase de Object es Object class.
La metaclase permite tratar las clases como objetos. Al tener información sobre la
definición de una clase, la metaclase implementa y ejecuta los métodos de clase, en particular
los de creación de objetos. Por ejemplo, el método palo:numero: de la clase Carta (figura 1)
permite crear objetos de esta clase, en la figura 2 puede observarse que este método está
contenido en el diccionario de métodos de Carta class, la metaclase de carta.
6
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
Figura 2.- La metaclase de Carta (Carta class) y la clase Metaclass
Cada metaclase tiene una única instancia, su clase. A su vez todas las metaclases son
objetos de la clase Metaclass.
Metaclass es objeto (instancia) de Metaclass class. Puesto que Metaclass class es una
metaclase será instancia de Metaclass. En la siguiente figura podemos ver las relaciones
instancia_de que se establecen.
Metaclass
Carta class
Carta
7 de bastos
Metaclass class
Cada metaclase se responsabiliza de los métodos de clase de su clase. De forma que cuando
se crea una clase, se crea primero su metaclase y se almacena en ella la definición de la clase.
En la figura que sigue se observa de quién es responsabilidad cada método
7
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
Carta class
new
palo:numero:
Carta
palo
numero
new
palo:numero:
palo
palo: ‘bastos’
numero: 7
Pero a su vez, los métodos de clase, al igual que los de instancia, también se heredan. Es
decir, igual que existe una jerarquía de herencia de clases, existe un jerarquía de herencia de
metaclases. Es por esta jerarquía de metaclases por la que se heredan los métodos de clase.
Metaclass
Object class
Object
Carta class
Carta
7 de bastos
Metaclass class
Pero, ¿de quién hereda Object class, Metaclass y Metaclass class? La cosa se complica.
Aparecen dos nuevas clases: Behavior y Class. Todas las metaclases heredan de Class, que a
su vez hereda de Behavior. Metaclass también es subclase de Behavior.
De este modo los métodos de instancia definidos en Object se utilizan tanto para manipular
los objetos de una clase como las clases y la metaclases.
La consecuencias de esta estructura es que los métodos de instancia de Class se transforman
en métodos de clase del resto de la jerarquía. Class sería un buen lugar para contener el
método new como método de intancia, pero si fuera así no se podría utilizar new para crear
clases y metaclases. New se define como método de instancia en Behavior y de este modo
sirve tanto para crear objetos de una clase normal, al ser heredado por la vía de Class como
método de clase, como para crear clases y metaclases.
8
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
Object
Behavior
Metaclass
Carta
Class
Object class
Carta class
Behavior class
Metaclass class
Class class
Veámoslo de forma abstracta (no sucede exactamente de este modo). Supongamos que
queremos crear la clase Bolígrafo. Habría que crear primero su metaclase:
Metaclass new name:Boligrafo.
New es en este caso un método de clase de Metaclass, luego debe ser ejecutado por Metaclass
class. Como Metaclass class hereda de Behavior se crea la correspondiente metaclase.
Name es un método de instancia de Metaclass, luego será Metaclass el que lo resuelva.
Una vez creada la metaclase ya podemos crear la clase:
(Bolígrafo class) new
Este new va dirigido a una metaclase luego sería un método de instancia de Metaclass y sería
Metaclass la responsable de él. De nuevo se puede ejecutar el new de Behavior o se puede
redefinir en Metaclass, en este caso se redefine en Metaclass para que solo se pueda tener una
clase para cada metaclase.
Ya creada la clase se le pueden mandar mensajes para definir las variables y los métodos:
Bolígrafo addInstVarName: ‘tinta’
El método addInstVarName: añade una variable de instancia (ver figura 1). Se trata de un
método de clase, pero como en realidad manipula la clase como un objeto cualquiera está
implementado en Class y es heredado por Bolígrafo class.
La finalidad de todo este lío es:
-
Poder tratar las clases como objetos: Class hereda indirectamente de Object, luego los
mensajes que entiende un objeto, que determinan su comportamiento y modifican su
estado, también son válidos para una clase.
-
Poder heredar los métodos de creación de instancias: El método new, para crear
instancias, está implementado en Behavior. Como Class y Metaclass heredan de
9
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
Behavior, heredan este método y pueden crearse clases y metaclases. Todas las
metaclases heredan de Class, y entre ellas está la metaclase Object class. Object class
también hereda el método new, por lo cual también puede crearse cualquier objeto
(recordemos que son las metaclases las que responden al mensaje new y son las que en
realidad crean objetos)
10
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
11
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
3. Herencia en JAVA
3.1.
Herencia de interfaces
Una interface es una forma de declarar un tipo, de tal forma que éste conste de constantes y
signaturas de métodos sin implementar. La interface define un tipo que puede ser usado para
declarar variables.
Una interface podrá ser implementada por clases diferentes que pueden o no tener relación de
herencia entre sí.
La interface puede considerarse similar a una clase abstracta pero se diferencian en lo
siguiente:
- La interfaz carece de implementación. En general una clase abstracta posee métodos
abstractos, que deberán ser implementados por las subclases, y métodos implementados
en ella.
- Una interfaz puede heredar de más de una interfaz.
- Las subclases de una clase abstracta tendrán entre sí alguna relación de
generalización/especialización. Sin embargo, las clases que implementan una interfaz
pueden no tener ninguna relación de herencia.
Supongamos el siguiente problema: los datos de los clientes de una empresa se encuentran en
diferentes bases de datos con diferentes estructuras. Se desea unificar el servicio de envío de
correo electrónico a los clientes independientemente de la base de datos.
Class Cliente
String nombre
String apellidos
String email
Enviar (String mensaje)
Class ListaDeClientes
Cliente [] clientes
Abstract ObtenerTodosLosClientes
AñadirCliente (Cliente c)
OrdenarClientes
EnviarATodos (String mensaje)
{aCadaCliente.enviar (mensaje)}
AñadirListaDeClientes (ListaDeClientes lista)
Class ListaDeClientesOracle extends ListaDeClientes
ObtenerTodosLosClientes
{para cada cliente obtenido de la BD crear unCliente}
Class GestorCorreoClientes
ListaDeClientes listaGlobalDeClientes
ListaDeClientesOracle listaOracle
String mensaje
EnviarATodos
{listaOracle.obtenerTodosLosClientes;
listaGlobalDeClientes.añadirListaDeClientes (listaOracle);
12
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
listaGlobalDeClientes.ordenarClientes();
listaGlobalDeClientes.enviarATodos (mensaje)}
Supongamos ahora que los Clientes a los que hay que enviar los mensajes son difícilmente
unificables en una clase y que, además, para cada tipo de clientes se utiliza un programa de
correo y un protocolo diferente de envío. En este caso recurrimos a una interface.
Interface Cliente
Enviar (String mensaje)
Class Empresa implements Cliente
String nombre
String director
String email
Enviar (String mensaje)
Class Individuo implements Cliente
String apellidos
String nombre
String email
Enviar (String mensaje)
El método obtenerTodosLosClientes de ListaDeClientes debería también modificarse para
crear una u otra clase de clientes. Otra solución sería crear una subclase de ListaDeClientes
por cada tipo de cliente.
Las interfaces pueden ‘heredarse’ y además de forma múltiple.
Interface Empresario
Regalar (String mensaje)
Interface Persona
Felicitar (String mensaje)
Interface ClienteEmpresario extends Cliente, Empresario
Interface ClientePersona extends Cliente, Persona
Ahora podríamos hacer que las clase Empresa implemente ClienteEmpresario y la clase
Indiciduo implemente ClientePersona. Evidentemente habría que implementar las
operaciones pertinentes en cada clase.
No existe la herencia múltiple en Java, aunque una clase puede heredar de otra e implementar
al mismo tiempo los métodos de una Interface.
interface Alimentos {
void comer(String c);
void beber(String b);
}
interface Ejercicios {
void correr(int k);
}
class Dieta implements Alimentos { // uso de una interface
13
Programación Dirigida a Objetos . MATERIAL COMPLEMENTARIO
private String comida;
void comer(String c) { comida= c; };
void beber(String b) { System.out.println(b);}
}
class Dieta implements Alimentos, Ejercicios { //uso de varias interfaces: simulación de
herencia múltiple
private String comida;
public int totalCorrido = 40;
void comer(String c) { comida= c; };
void beber(String b) { System.out.println(b);};
void correr(int k) { return ( totalCorrido+ k) };
}
En realidad, hay dos formas de “simular” en Java la herencia múltiple y podemos verla con
el ejemplo del Ornitorrinco
1) Se toman métodos de varias interfaces
interface Mamifero {...}
interface Oviparo {...}
class Ornitorrinco implements Mamifero, Oviparo { ...}
2) Se hereda de una clase y se toman métodos de una o más interfaces
interface Mamifero {...}
class Oviparo {...}
class Ornitorrinco extends Oviparo implements Mamifero {...}
En realidad no se trata de herencia múltiple puesto que las interfaces no permiten heredar
ninguna implementación, pero al tener que implementar la interface Mamífero, la clase
Ornitorrinco se puede comportar como un Mamífero allí donde se hayan declarado variables
de tipo Mamífero. La interfaces dan una mayor potencia al polimorfismo al permitir que
clases que no tienen ninguna relación de herencia puedan actuar de modo polimórfico.
Las interfaces tienen una última ventaja de diseño: se puede proponer una interfaz como el
protocolo mínimo que deben cumplir las clases para poder interactuar. Esto permite anticipar
el comportamiento de clases que aún no han sido definidas. Por ejemplo, en JAVA Collection
es una interfaz de modo que cualquier clase que la implemente se podrá comportar como una
colección.
14
Descargar