Está en la página 1de 19

Creado el 16/04/09

2 Introduccin a
Herencia de Clase

Conceptos Principales:

Herencia de clase Subclase para reutilizacin: extensin, especializacin, generalizacin Solapando mtodos heredados Encapsulacin Visual Form Inheritance (VFI) Jerarqua de clase del VCL de Delphi Navegacin (enlazado) entre objetos Navegacin sobre un diagrama de clase UML Visibilidad para paso de mensaje

Aprendiendo OOP con Delphi

Pgina 1 de 19

Creado el 16/04/09

Introduccin
En el captulo 1 hablamos sobre tres perspectivas sobre objetos: objetos como entidades independientes, objetos como entidades derivadas y objetos como entidades que interactan. En ste captulo realizaremos una primera aproximacin a los objetos como entidades derivadas usando una de las facilidades del RAD de Delphi, llamada Visual Form Inheritance (VFI). Esto nos permite definir un formulario y luego usarlo como la base de futuros formularios a travs de la herencia. Utilizaremos VFI para reutilizar un formulario existente a travs de la herencia y luego ampliaremos y especializaremos estos formularios derivados a travs de nuestro cdigo. Y ya que los objetos de forma aislada no tienen mucha utilidad, analizaremos brevemente la interaccin entre estos objetos.

Ejemplo 2.1. Subclaseado a travs de Visual Form Inheritance (VFI)


En ste ejemplo, usaremos VFI para crear la estructura de la Figura 1. Por ahora mostraremos slo los nombres de clases y suprimiremos los atributos y los mtodos en los diagramas de clases. Ms tarde los diagramas se mostrarn con ms detalle.

Figura 1: Herencia a travs de VFI

Ejemplo 2.1 paso 1: El Form maestro


Inicie una nueva aplicacin. Escribiremos un manejador de eventos para con ste formulario (TForm1 en Figura 1) visualizar otros formularios (TForm3 y TForm4) en un momento, pero por ahora slo cambiaremos el tamao de ste TForm1 a 300 x 150.

Ejemplo 2.1 paso 2: La Clase base


VFI es el proceso RAD para la creacin de una plantilla de formulario, la clase base, y despus la herencia (o subclaseado) de otros formularios desde l. Primero creamos la clase base, usando File | New | Form, aadiendo un segundo form al proyecto ( TForm2 en la Figura 1) y colocando un botn dentro del mismo. Esto crear una clase base desde la que heredaremos otros dos subformularios.

Aprendiendo OOP con Delphi

Pgina 2 de 19

Creado el 16/04/09

Haga el form de un tamao conveniente (sobre 200 x 100) y cree un manejador para el evento OnClick del botn button1 en Unit2:
13 implementation 14 {$R *.dfm} 15 16 17 18 19 procedure TForm2.Button1Click(Sender: TObject); begin ShowMessage ('Button ' + (Sender as TButton).Caption + ' clicked'); end; // end procedure TForm2.Button1Click end. // end Unit2

Los forms descendientes (TForm3 y TForm4 en la Figura 1) heredern ste mtodo, y usaremos el parmetro Sender para identificar el Caption del botn que ha sido pulsado. La lnea 17 es la primera aparicin del parmetro Sender y lo veremos unas cuantas veces ms a lo largo de ste mdulo.

Ejemplo 2.1 paso 3: Un Form derivado


TForm2,

definido en el paso 2, es el formulario base desde el cual derivaremos futuros formularios.

Para crear TForm3 en Delphi 4/7, seleccione la secuencia de men File | New | Other y luego seleccione la pestaa denominada Project1 (o Project2, 3, ...., dependiendo del nombre de su proyecto actual). Hasta el momento, todos sus formularios han sido derivados desde TForm. Debido a que estamos usando TForm2 como base, Delphi deriva nuestro nuevo formulario, TForm3 en Unit3, desde TForm2 (lnea 7 anterior). Las Units se encapsulan las unas de las otras, y as para que la Unit3 pueda referirse a TForm2 en la declaracin de clases (lnea 7), Delphi inserta Unit2, el cual define TForm2, en la clusula global uses de la (lnea 5) Unit3.
1 unit Unit3; 2 interface 3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs, Unit2; 6 type 7 TForm3 = class(TForm2) // hereda desde TForm2, no TForm 8 private 9 { Private declarations } 10 public 11 { Public declarations } 12 end; 13 var 14 Form3: TForm3; 15 implementation 16 {$R *.dfm} 17 end.

Aprendiendo OOP con Delphi

Pgina 3 de 19

Creado el 16/04/09

hereda todos los campos de datos (propiedades) y caractersticas (mtodos y manejadores de eventos) desde TForm2, as que un botn, definido en TForm2, aparece como parte de la visualizacin del objeto Form3 (Figura 2) aunque no figure en la definicin de tipos de TForm3 (lneas 712). Usando el Inspector de Objetos, cambie el Caption del botn a btnForm3 y la posicin del form (propiedades Top y Left) para que no quede tapado por los dems formularios. No haga ms cambios sobre Form3 de momento.
TForm3

Figura 2: TForm3 derivado de TForm2

Ejemplo 2.1 paso 4: Otro Form derivado


Podemos heredar cualquier nmero de clases desde una clase existente, as que heredar un nuevo form y unit (TForm4 en Unit4) desde Form2 sigue el proceso que se muestra en el paso 3. Cambie el Caption del botn en TForm4 a btnForm4. Posicione los cuatro forms de manera que se vean todos, pero no cambie ms propiedades. La herencia significa que las subclases heredan todos los campos de datos y mtodos desde la superclase. Debido a que sta es una aplicacin RAD, las subclases tambin tienen por defecto los valores inciales de la superclase. Para ver esto cambie, digamos, el ancho del Form2. Los anchos de Form3 y Form4 cambian tambin. Si tiene dudas de lo que hemos hecho hasta ahora, estudie el cdigo para cada una de stas units.

Ejemplo 2.1 paso 5: Enlazando los forms


Ahora tenemos una estructura de herencia con un nmero de distintas clases. Sin embargo, una estructura de clase por s sola no sirve de mucho necesitamos introducir algunas pautas de interaccin entre las clases-. Queremos poder displayar Form3 y Form4 desde Form1. Podemos ampliar nuesto diagrama de clase para mostrar stas pautas (Figura 3).

Aprendiendo OOP con Delphi

Pgina 4 de 19

Creado el 16/04/09

Figura 3: Enlaces de comunicacin entre clases

La convencin UML usa puntas de flecha cerradas y sin relleno para herencia y puntas de flecha abiertas para enlaces de navegacin (tambin llamados enlaces de asociacin). La Figura 3 muestra puntas de flecha abiertas en los enlaces entre TForm1, TForm3 y TForm4, apuntando desde TForm1 a los otros dos forms. Esto refleja que Form1 puede acceder a Form3 y a Form4, pero no hay acceso disponible en la direccin inversa. Para implementar estos enlaces, retorne a la Unit1. Usando la paleta Component / Tool, coloque un botn en TForm1. Establezca su propiedad Name a btnShowForms y su Caption a Show Forms. Cree un manejador para el evento OnClick que enve mensajes a Form3 y Form4, haciendo que se muestren asmismos (lneas 2021). Presione <F9> para ejecutar el programa. Delphi mostrar una ventana de informacin, diciendo: Form Form1 references Form3 declared in Unit3 which is not in your USES list. Do you wish to add it? Seleccione Yes como respuesta. Ejecute de nuevo. Repite la pregunta, pero sta vez para la Unit4. Pulse Yes para aadir Unit4 a la clusula uses tambin. Delphi aade una clusula local uses Unit3, Unit4; a Unit1 (p.ej., en su implementacin privada y no en la pblica, seccin de interfaz) (lnea 16 a continuacin).
15 implementation 16 uses Unit3, Unit4; 17 {$R *.dfm} 18 procedure TForm1.btnShowFormsClick(Sender: TObject); 19 begin 20 Form3.Show; 21 Form4.Show; 22 end; // end procedure TForm1.btnShowFormsClick

Ejecute de nuevo el programa. El Form1 (slo l) aparece. Pulse en el botn para invocar al manejador del evento OnClick y Form3 y Form4 aparecern. Form2 no aparece porque no ha sido instrudo a mostrarse a s mismo. Un click sobre Form1 puede enviar un mensaje Show a Form3 y Form4 porque hay una asociacin entre TForm1 y TForm3 y entre TForm1 y TForm4 (Figura 3). ste enlace es posible gracias a la clusula uses en la Unit1, la cual lista Unit3 y Unit4 (lnea 16 anterior).

Aprendiendo OOP con Delphi

Pgina 5 de 19

Creado el 16/04/09

Pulse el botn en Form3 o Form4, y un mensaje identificando el botn por su Caption aparece (Figura 4).

Figura 4: Una confirmacin de que btnForm3 ha sido pulsado

Ni TForm3 ni TForm4 tienen definidos campos de datos ni operaciones. Sin embargo ambos estn derivados de TForm2, el cual define un campo de datos TButton y su manejador de eventos OnClick, y as tanto TForm3 como TForm4 heredan el botn y su manejador de eventos desde TForm2. As, a travs de la herencia, TForm3 y TForm4 reutilizan TForm2 y en ste caso no necesitan ningn cdigo propio. Establecemos distintos Caption para los botones en Form3 y Form4 para mostrar que est funcionando el cdigo con diferentes objetos. Para identificar estos objetos usamos el parmetro Sender en la lnea 17 del manejador de eventos del evento OnClick del Form2 (ejemplo 2.1, paso 2). Ya que cada instancia tiene su propio dato, Form3 y Form4 tambin tienen sus propios valores para Top, Left, etc, y es por esto por lo que pueden ocupar posiciones distintas en la pantalla. Almacene ste proyecto, ya que lo usaremos como punto de inicio para los ejemplos 2.2 y 2.3.

Ejemplo 2.1: Sumario


Los principales principios OO en ste ejemplo son la herencia y la comunicacin. TForm2 hereda el conocimiento de cmo ser un formulario de TForm. ste aade su propio campo de datos (un botn) y un mtodo (el manejador del evento OnClick del botn). TForm3 y TForm4 estn ambos derivados desde TForm2 y ninguno de ellos aade nada a s mismos. An as, debido a la herencia, cada uno tiene el conocimiento de cmo ser un formulario (desde la clase de la VCL TForm), y un botn con su manejador de eventos (desde TForm2). Tambin hemos creado enlaces de navegacin (asociacin simple ) entre un formulario y otro. Desde la perspectiva de Delphi, hemos visto cmo con VFI podemos definir un formulario base ( Form2 en nuestro caso) y entonces derivar el resto de formularios desde l. Obtenemos toda la funcionalidad disponible en el formulario base sin tener que redefinir formularios separadamente como en el captulo 1. Los botones en los formularios derivados siempre invocan al manejador de eventos del formulario base. Por tanto VFI es una til ilustracin de OO y herencia y de la forma en que el subclaseado puede promover la reutilizacin.

Ejemplo 2.2. Subclaseado para Extensin


En el ejemplo 2.1 no aadimos ningn cdigo a las units 3 4. A consecuencia de la herencia cada uno de sus botones usa el mismo manejador de eventos, el que se hereda desde el formulario base. Sin embargo, una subclase tambin puede extender la funcionalidad de la superclase. El subclaseado para extensin implica dar a una subclase caractersticas aadidas en adicin a las que hereda. En ste ejemplo daremos a cada subclase su propio mtodo: cada uno de ellos manipular la posicin del Form1 (Figura 5).

Aprendiendo OOP con Delphi

Pgina 6 de 19

Creado el 16/04/09

Figura 5: Subclaseado para extensin y adicin de enlaces de navegacin bidireccionales

Reflejamos la navegabilidad en nuestro diagrama de clases UML a travs de puntas de flecha de cabeza abierta sobre los enlaces de asociacin (Figura 5). Aqu mostramos los atributos y mtodos relevantes que extienden la superclase. Para presentar un estilo ligeramente diferente, las rutas de herencia son mostradas como flechas separadas, y no como rboles grficos combinados como en los anteriores diagramas.

Ejemplo 2.2 paso 1. Extensin en una Subclase


Comience con el programa del ejemplo 2.1. Aada un TCheckBox a Form3 (Figura 6), asgnele el Caption Top, y cree un manejador de eventos OnClick haciendo doble click sobre el CheckBox:
procedure TForm3.CheckBox1Click(Sender: TObject); begin inherited; if CheckBox1.Checked then Form1.Top := 10; end;

Existe una ligera diferencia aqu con respecto a nuestros anteriores manejadores de evento. Como TForm3 est derivado desde TForm2 (y no desde TForm), Delphi automticamente inserta el estamento inherited como primera lnea de programa en ste manejador de evento. Djelo por ahora aunque no pinte nada aqu -discutiremos el significado de inherited en el prximo ejemplo-. TForm3 ahora hereda un botn y un manejador de evento desde TForm2 y aade un CheckBox y otro manejador de evento por s mismo.

Aprendiendo OOP con Delphi

Pgina 7 de 19

Creado el 16/04/09

Figura 6: Extendiendo Form3 con un componente CheckBox

Figura 7: Extendiendo Form4 con un componente UpDown

Ejemplo 2.2 paso 2. Una Extensin distinta en otra Subclase


Un aspecto importante del subclaseado para extensin es que cada subclase puede extender la superclase de forma distinta. Para ver esto, aada un componente UpDown (pestaa Win32) a Form4 (Figura 7), establezca su propiedad Wrap a True, y cree un manejador de evento OnClick:
procedure TForm4.UpDown1Click(Sender: TObject; Button: TUDBtnType); begin inherited; if Button = btNext then Form1.Top := Form1.Top - 20 else Form1.Top := Form1.Top + 20; Form3.CheckBox1.Checked := False; end;

Aqu de nuevo, Delphi automticamente inserta el estamento inherited. Incluimos un mensaje desde Form4 a Form3 para limpiar el CheckBox cada vez que Form4 reposiciona Form1.

Ejemplo 2.2 paso 3. Comunicacin Bidireccional


Cuando usamos VFI frecuentemente enviamos mensajes desde un formulario a otro, y en los pasos anteriores tanto Form3 como Form4 comunican con Form1, y Form4 comunica con Form3. Necesitamos por tanto enlaces entre formularios, y Delphi normalmente puede establecer estos enlaces por nosotros. Para ver esto, ejecute el programa. Delphi proporciona una serie de mensajes informndonos de que varios formularios usan otros formularios pero no los incluye en sus respectivas clusulas uses. Seleccione Yes cada vez que Delphi lo pida para insertar el valor adecuado en las clusulas uses. Advierta que Delphi inserta clusulas uses locales en Unit3.pas y Unit4.pas (p.ej., en la seccin de implementacin). Intente de nuevo ejecutar el programa. Esta vez, cuando usted muestra Form3 y Form4 picando sobre Form1, cada uno de ellos tiene la estructura que deriva desde Form2 y tambin tiene la suya propia, extensin individual que acabamos de introducir (figuras 6 y 7).

Ejemplo 2.2. Sumario


Este ejemplo introduce el subclaseado para extensin. El uso de la herencia para extensin tiene las siguientes caractersticas:

La subclase hereda toda la funcionalidad de la superclase, La subclase aade nueva funcionalidad, La subclase no hace cambios en la funcionalidad de la superclase (que hereda).

Aprendiendo OOP con Delphi

Pgina 8 de 19

Creado el 16/04/09

El subclaseado para extensin es lo que los programadores suelen tener en mente cuando se exaltan las virtudes de la herencia como aproximacin importante al problema de la reutilizacin. Tambin usamos ste ejemplo como una oportunidad para ver brevemente una navegacin bidireccional entre objetos y para ver la representacin de la navegacin en un diagrama de clases.

Ejemplo 2.3. Subclaseado para Especializacin


Otro uso muy importante de la herencia es el subclaseado para la especializacin. Aqu, la subclase es de algn modo un caso especial de superclase y sobreescribe tanto como extiende los mtodos de la superclase. Daremos a Form3 su propio manejador de eventos Button1Click adicional para extender la operacin del manejador de eventos que l hereda.

Ejemplo 2.3 paso 1. Especializando a TForm3


Abra el proyecto desde el ejemplo 2.1. TForm3 y TForm4 son clases vacas que heredan toda su funcionalidad (manejador de eventos OnClick de TForm2) desde TForm2. Vamos a especializar ste manejador de eventos en las subclases aadiendo funcionalidad extra a ellas en TForm3 y en TForm4. En modo diseo, seleccione Form3 y haga doble click sobre Button1. Delphi crea un esqueleto de manejador de eventos. Aada la siguiente lnea de cdigo adicional (lnea 17).
1 unit Unit3; 2 interface 3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs, StdCtrls, Unit2; 6 type 7 TForm3 = class(TForm2) 8 procedure Button1Click(Sender: TObject); 9 end; 10 var 11 Form3: TForm3; 12 implementation 13 {$R *.dfm} 14 procedure TForm3.Button1Click(Sender: TObject); 15 begin 16 inherited; 17 ShowMessage ('Otro mensaje desde ' + (Sender as TButton).Caption); 18 end; 19 end.

Ejecute ste programa. Pulsar el botn en Form3 nos muestra el mensaje original generado por el manejador de eventos de Button1Click de TForm2 (ejemplo 2.1, paso 2, lnea 17). La aceptacin de ste mensaje nos lleva entonces a otro mensaje generado por el manejador de eventos Button1Click de TForm3. Por contraste, la pulsacin del botn en Form4 nos da slo la funcionalildad derivada desde Form2. As que con TForm3 tenemos un caso donde usamos la herencia para aadir a la funcionalidad heredada, un proceso llamado especializacin.

Aprendiendo OOP con Delphi

Pgina 9 de 19

Creado el 16/04/09

Veamos qu est pasando aqu. Cuando hace doble click sobre el Button1 en Form3 durante el modo diseo, Delphi crea un nuevo manejador de eventos de Button1 como mtodo de TForm3 (declarado en la lnea 8 anterior). Para cualquier objeto de clase TForm3, el manejador de evento OnClick en TForm3 sobreescribir el manejador de eventos heredado en TForm2 (por contraste, TForm4 no declara su propio manejador de eventos, as que Form4 por tanto sube un nivel y ejecuta el manejador de eventos heredado desde TForm2). Delphi tambin genera el esqueleto del manejador de eventos (lneas 1416 y 18 arriba). Lo que difiere aqu de los esqueletos de manejadores de evento que vimos en el captulo 1 es que Delphi inserta un estamento inherited (lnea 16 anterior y tambin en los manejadores de evento del ejemplo 2.2). Por qu pasa esto? Normalmente, con la especializacin, nosotros queremos aadir alguna funcionalidad a la disponible desde la superclase. Sin embargo, en el prrafo anterior dijimos que el manejador de eventos en la clase derivada reemplaza completamente al manejador de eventos definido en la superclase. La palabra clave inherited en el mtodo de la subclase llama al correspondiente mtodo en la superclase. Por tanto el mtodo de la subclase sobreescribe completamente al mtodo de la superclase. Si todava deseamos que el mtodo (sobreescrito) de la superclase funcione, insertamos la palabra clave inherited, normalmente como primer estamento en el (sobreescrito) mtodo de la subclase. Habiendo llamado y ejecutado al mtodo de la superclase, ahora nos movemos a la lnea 17, la cual proporciona las operaciones de especializacin. Por inters, puede desear cambiar el orden de las lneas 16 y 17 y luego ejecutar el programa de nuevo. El mensaje desde el Button1Click de TForm3 ahora aparece antes que el de TForm.

Ejemplo 2.3 paso 2. Especializando TForm4


Podemos dar a TForm4 una especializacin diferente a TForm3. Podemos tambin sobreescribir completamente el mtodo de la superclase eliminando el estamento inherited que Delphi inserta automticamente. Seleccione Form4, haga doble click sobre su botn Button1 y cree el siguiente manejador de evento, recordando eliminar el estamento inherited. Debido a que ste manejador de evento se refiere a Unit1, sta unit tambin necesita una clusula uses Unit1. Puede insertarla usted mismo (lnea 17 debajo) o dejar que lo haga Delphi como antes (Unit3 no se refiere a Unit1, y por tanto no insertaremos una clusula uses Unit1 en el paso 1 anterior).
16 implementation 17 uses Unit1; 18 {$R *.dfm} 19 procedure TForm4.Button1Click(Sender: TObject); 20 begin 21 Form1.Top := 300; 22 end;

Ejecute ste programa. Pulsando sobre el botn en Form4 reposicionamos Form1 con su propiedad top a 300 pixels sin displayar ningn mensaje. El manejador de eventos en la superclase no se ejecuta porque el manejador de eventos OnClick del Button1 de TForm4 (lneas 1518 anteriores) no contiene la palabra clave inherited y por tanto no se invoca al manejador de eventos OnClick del Button1 de la superclase (TForm2).

Aprendiendo OOP con Delphi

Pgina 10 de 19

Creado el 16/04/09

Ejemplo 2.3. Sumario


En ste ejemplo hemos explorado brevemente la herencia para especializacin, donde una subclase especializa la funcionalidad de una superclase. Esta especializacin puede ser cdigo adicional al del mtodo de la superclase, en cuyo caso el mtodo de la subclase contiene la palabra clave inherited. La especializacin tambin puede reemplazar completamente al mtodo de la superclase, en cuyo caso el mtodo de la subclase no contiene la palabra clave inherited. Una precaucin: cuando reemplazamos completamente al mtodo de la superclase en la subclase afectamos al subtipado de la subclase. No hemos tratado con el subtipado todava. Lo haremos en breve y entonces veremos que meterse con el subtipado debera hacerse slo despus de haberlo pensado cuidadosamente ya que ste invalida el polimorfismo, un concepto central de la OO.

Ejemplo 2.4. Declaraciones Globales y Locales


Advierta que con un formulario generado va RAD, la unit que define la clase (Form) tambin declara una referencia global a una instancia de esa clase en su seccin de interfaz. Esto hace posible a cualquier unit acceder a cualquier formulario declarado en otra unit proporcionando la adecuada clusula uses. Para ilustrar la encapsulacin, podemos mover la declaracin global en la Unit4 a la seccin de implementacin para ver qu ocurre (lneas 1213 debajo) (la seccin de implementacin es accesible slo a su propia unit).
1 unit Unit4; 2 interface 3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs, StdCtrls, Buttons, ComCtrls, Unit2; 6 type 7 TForm4 = class(TForm2) 8 procedure Button1Click(Sender: TObject); 9 end; 10 implementation 11 uses Unit1; 12 var 13 Form4: TForm4; 14 {$R *.dfm} 15 procedure TForm4.Button1Click(Sender: TObject); 16 begin 17 Form1.Top := 300; 18 end; 19 end.

Cuando intentamos compilarlo, obtenemos dos mensajes de error. Aunque Unit1 tiene a Unit4 en su clusula uses, la Unit1 ve a Form4 como a un identificador no declarado porque Form4 est ahora declarado en la seccin de implementacin (privada) de Unit4 y no en su (pblica) seccin de interfaz. Para enfatizar que una declaracin en la seccin de implementacin es slo para el uso de la unit local, Delphi genera una advertencia de que la variable Form4 est declarada pero no es usada en Unit4. Restaure la declaracin de la variable a su lugar correcto antes de la palabra clave implementation y el programa funcionar correctamente de nuevo.

Aprendiendo OOP con Delphi

Pgina 11 de 19

Creado el 16/04/09

Aunque mostramos la herencia para extensin y la herencia para especializacin separadamente en los ejemplos 2.3 y 2.4, ambas suelen aparecer combinadas. Los programas OO tpicamente suelen incluir una sofisticada red de derivacin (a travs de la herencia y la composicin) y comunicacin (a travs de la asociacin).

Ejemplo 2.5. Jerarquas y Generalizacin


Tanto la extensin como la especializacin trabajan ambas desde la perspectiva de una clase existente que reutilizamos para encontrar un nuevo requerimiento mediante la extensin o la especializacin de alguna forma. La generalizacin jerrquica, por otro lado, examina lo que se reparte entre un nmero de clases existentes (p.ej., lo que es general entre ellas) y entonces mueve ste cdigo comn fuera de las clases existentes dentro de una superclase. Mediante la generalizacin de stas caractersticas compartidas en una superclase de la que las subclases heredan, stas caracteristicas compartidas necesitan ser codificadas slo una vez (en la superclase), y pueden entonces ser reutilizadas por las subclases. Frecuentemente la superclase, como TForm2 en los ejemplos anteriores, no est siempre instanciada pero sirve en su lugar simplemente como una forma de almacenar las caractersticas compartidas por sus subclases. Los mecanismos tanto para la extensin como para la especializacin y la generalizacin son casi los mismos y las distinciones entre estas normalmente resultan de un particular grupo de circunstancias. La extensin o especializacin frecuentemente comienza con una clase existente la cual est modificada para cumplir un nuevo requerimiento. La generalizacin frecuentemente comienza con la identificacin de caractersticas comunes entre subclases y resulta en la creacin de una probable clase artificial, conteniendo esas caractersticas compartidas. Al igual que en los ejemplos anteriores, podemos decir que TForm3 y TForm4 ambos extienden o especializan Tform2. Tambin podemos decir que TForm2 generaliza TForm3 y TForm4 ya que TForm2 contiene las operaciones y datos que aparecen tanto en TForm3 como en TForm4 (excepto donde el mtodo Button1Click de TForm4 sobreescribe al mtodo Button1Click de TForm2). As que cuando analizamos un sistema y encontramos un grupo de objetos, merece la pena buscar datos y comportamientos que los distintos objetos comparten y entonces generalizar estos datos y comportamientos en una jerarqua para obtener los beneficios de la reutilizacin.

La VCL de Delphi (un ejemplo de Subclaseado)


Mientras que los principios que hemos visto en los ejemplos de subclaseado han sido importantes, los programas en s mismos eran triviales. Para ver una aplicacin ms efectiva del subclaseado el cual implica la extensin y la generalizacin, y en una obvia menor medida a la especializacin, no necesitamos ms que ver la Visual Component Library (VCL) de Delphi.

Aprendiendo OOP con Delphi

Pgina 12 de 19

Creado el 16/04/09

La VCL1 proporciona los componentes (a travs de la paleta Component / Tool) para la construccin de la interfaz de usuario. Si miramos los componentes disponibles de la paleta Component / Tool, advertimos que todos tienen algunos grados de similaridad y diferencia. Comparando un TButton y un TLabel, vemos que existen similitudes entre ellos: ambos son visibles en un formulario en una posicin especfica. Pero tambin vemos grandes diferencias. Sin embargo, si comparamos un TButton y un TBitBtn vemos que las similitudes son mucho mayores. Cmo acomodamos distintos grados de similaridad y diferencia de forma efectiva? En principio, nos gustara codificar slo una vez todo aquello que es idntico en ambos componentes y usar nuevo cdigo exclusivamente para las caracteristicas adicionales en el nuevo componente. Los sistemas OO hacen esto posible a travs de la jerarqua de clase y la herencia. La Figura 8 muestra una muy simplificada representacin de la jerarqua de clases de la VCL de Delphi (un juego de clases de utilidades estndar mientras que la VCL tiene una extensiva y profunda jerarqua. Las jerarquas de clases que nosotros definimos son usualmente mucho ms simples).

Figura 8: Un diagrama parcial, muy resumido, de la jerarqua de clases de la VCL de Delphi

En una jerarqua como sta buscamos los elementos comunes entre los distintos componentes y entonces codificamos stas igualdades en una (posiblemente artificial) superclase. Siguiendo sta aproximacin, tomamos todo lo que es comn entre un TLabel, un TButton y un TForm y lo codificamos en una nueva clase, TControl. Ahora vemos qu hay en comn entre TTimer, TControl y TMenu y lo codificamos en una nueva clase, TComponent, y as continuamos en la jerarqua. Nunca podremos instanciar las clases de nivel ms alto tales como TControl, TComponent o TPersistent. En su lugar proporcionamos la oportunidad de codificar caractersticas comunes una sla vez en un ancestro. Todos los descendientes entonces usan ste cdigo en lugar de escribirlo desde cero cada vez.

Delphi 6 y posteriores tambin contiene la librera CLX, introducida para portabilidad con Linux. La versin 8 incluye la librera .NET. Aqu slo trabajaremos con la original VCL que es comn en todas las versiones.

Aprendiendo OOP con Delphi

Pgina 13 de 19

Creado el 16/04/09

Mirando especficamente en la VCL, todo lo que es fundamental para todos los componentes y objetos aparece lo ms alto posible en la jerarqua, en la clase base. Todas las clases Delphi deben ser capaces de crear y destruir instancias de s mismas y por tanto TObject, el cual es la raz de la jerarqua de herencia de Delphi, tiene estas habilidades. Todos los objetos Delphi, excepto los objetos Exceptions y TStream, pueden ser guardados, y por tanto el siguiente nivel de la jerarqua separa los que pueden ser almacenados (TPersistent) de los objetos Exceptions y TStream. Algunas clases persistentes son componentes y otras no, y por tanto el tipo TComponent aparece bajo TPersistent en la jerarqua. TComponent introduce la habilidad de aparecer en la paleta Component / Tool y de ser manipulado en el Diseador del Form, y propiedades tales como Name. Tambin hereda la capacidad de ser almacenado desde TPersistent y de crear y destruir objetos desde TObject a travs de TPersistent. Algunos componentes son visuales, y otros, tales como TTimer o TMenu, no lo son. Los componentes visuales son visibles en tiempo de ejecucin y por tanto necesitan capacidades adicionales tales como Left y Top para dar su posicin en el formulario, los comentarios (propiedad hint) tipo pop-up y la habilidad de responder a acciones del ratn. Estas habilidades estn empaquetadas en TControl. Yendo ms abajo en la jerarqua finalmente llegamos a los actuales componentes que usamos en nuestros programas, tales como TLabel y TButton. Estos heredan todas las capacidades disponibles en TControl el cual a su vez hereda las capacidades de TComponent, el cual a su vez hereda todas las capacidades de TObject. Las habilidades comunes son codificadas en lo ms alto de la jerarqua, y estn disponibles para todas las clases inferiores que bajan por la jerarqua. Cada nuevo nivel en la jerarqua slo necesita codificar las habilidades adicionales y no necesita repetir lo que ya est disponible desde arriba. Por tanto, la caracterstica ms general es la que se codifica en el nivel ms alto de la jerarqua, y la ms especializada es la que se codifica en el nivel ms bajo de la jerarqua. Esto nos da pie a frases como generalizacin de la jerarqua y al trmino generalizacin que UML usa cuando se refiere a la herencia. Como vimos, TControl introduce propiedades para Left y Top, y por tanto l y todos sus descendientes tienen las propiedades Left y Top. Volviendo a la Figura 8, vemos que TControl, TLabel, TButton, TForm y TBitBtn tienen todos las propiedades Left y Top. Sin embargo, TMenu, TComponent y TObject, los cuales no son descendientes de TControl, no heredan las propiedades Left y Top.

Ayuda sobre la Jerarqua VCL


La ayuda en lnea proporciona suficiente documentacin sobre los componentes VCL. Para explorarla, coloque un Timer en un formulario, seleccione el Timer y presione <F1> para activar la ayuda. Aparece una breve descripcin (Figura 9). Cerca de la parte superior de la pantalla hay una lista: Hierarchy, Properties, Methods, Events, Using Ttimer. Seleccione Hierarchy. La pantalla (Figura 10) confirma la jerarqua ilustrada en la Figura 8:

Aprendiendo OOP con Delphi

Pgina 14 de 19

Creado el 16/04/09

Figura 10: Posicin de Ttimer en la jerarqua VCL tal como se muestra en la ayuda de Delphi 7

Figura 9: Ayuda de la VCL de Delphi para el componente TTimer en Delphi 6

Si seleccionamos en enlace Properties, vemos una pantalla de las propiedades que TTimer declara por s mismo y aquellos que hereda desde TComponent (Figura 11). Similarmente podemos obtener una vista de los mtodos de TTimer (Figura 12). Esta es una lista mucho mayor que la de propiedades, y si bajamos por la lista veremos los mtodos de cada uno de sus ancestros.

Figura 11: La ayuda muestra las propiedades locales y heredadas de TTimer

Figura 12: Una vista parcial de los mtodos de TTimer

Aprendiendo OOP con Delphi

Pgina 15 de 19

Creado el 16/04/09

Algunos Comentarios Concluyentes sobre la Herencia


Distintos Tipos de Herencia
En ste captulo hemos visto la herencia para el subclaseado. Tambin hay otra forma de herencia, llamada subtipado. El subtipado est enlazado a los conceptos de enlazado tardo (o dinmico) y polimorfismo. El polimorfismo y el subtipado son importantes y poderosos aspectos de la orientacin a objetos que nos permiten, por ejemplo, introducir subtipos adicionales en un sistema con un impacto mnimo sobre el resto del programa, simplificando as futuros cambios. Retornaremos a ello ms tarde para ver esto en ms detalle.

Herencia Mltiple
Delphi, como Java y a diferencia de C++, no implementa la herencia mltiple. Para conseguir un efecto similar a la herencia mltiple en Delphi o Java, podemos usar la composicin y/o las interfaces. Volveremos a esto cuando veamos la composicin.

Composicin. Una alternativa a la Herencia


Aunque la herencia es muy potente y til, sta no es la nica forma de reutilizar clases existentes, y en algunas situaciones la composicin es preferible. La composicin es una forma de combinar un grupo de objetos para crear un super objeto. Delphi lo usa extensivamente para generar interfaces de usuario. En el ejemplo 1.2, por ejemplo, la interfaz de usuario (clase TfrmStructureDemo) est derivada desde el tipo TForm y contiene dos botones y dos mtodos (los manejadores de evento). Podemos ver esto mirando en la declaracin de tipos del programa:
type TfrmStructureDemo = class(TForm) btnYellow: TButton; btnBlue: TButton; procedure btnYellowClick(Sender: TObject); procedure btnBlueClick(Sender: TObject); end; btnYellow y btnBlue son btnYellow y un btnBlue. La

parte de la clase TfrmStructureDemo: TfrmStructureDemo TieneUn (HasA) Figura 3 del captulo 1 implica composicin. Como vimos en la Figura 5 del captulo 1, podemos redibujar ste diagrama para enfatizarla, usando una cabeza de diamante para indicar composicin (Figura 13 debajo). Usamos indicadores de multiplicidad sobre el enlace para mostrar que la clase TfrmStructureDemo est compuesta de dos botones Tbuttons.

Figura 13: Un formulario compuesto por dos botones

En resumen, la construccin de una clase desde una o ms clases es llamada composicin. La filosofa detrs de la composicin es similar a la de la herencia -ser capaz de reutilizar objetos y clases existentes, y por tanto escribir cdigo slo para caracteristicas adicionales-. En OO, la composicin y la herencia son las mejores herramientas para crear nuevas clases y para la reutilizacin. Investigaremos la composicin en los prximos captulos.

Aprendiendo OOP con Delphi

Pgina 16 de 19

Creado el 16/04/09

Sumario de Herencia de Clases (Subclaseado)

Figura 14: Herencia de Clases

Caractersticas de la Herencia de Clases


El subclaseado facilita la reutilizacin a travs de la programacin por diferencia ya que la subclase EsUna (IsA) superclase. Todos los campos de datos y mtodos de la superclase estn disponibles para sus subclases (excepto aquellos datos y mtodos en la superclase que tengan mbito privado). Ya que la subclase hereda la funcionalidad de la superclase, slo necesita implementar los campos de datos y mtodos adicionales y los mtodos que sobreescriben a los heredados (Figura 14).

Usos de la Herencia de Clases


Extensin Con la extensin, la subclase aade nueva funcionalidad (MasDatos, MasMetodos y DatosExtra, MetodosExtra en la Figura 14) pero no hace cambios en la funcionalidad existente en la superclase. Con la especializacin, la subclase es un caso especial de la superclase y por tanto extiende o sobreescribe algunos de los mtodos de la superclase (SobreescribeMetodos1 y SobreescribeMetodos2 en la Figura 14). El uso excesivo de la especializacin puede indicar la necesidad de redefinir la jerarqua, particularmente donde sta reemplaza completamente el comportamiento de la superclase, ya que esto invalida el subtipado. Para la generalizacin, cree una (posiblemente artificial) superclase. Elimine los datos comunes y funcionalidad encontrada en las subclases e implemente stas en la superclase (generalmente arriba). Haga esto repetidamente entre cada juego de niveles en la jerarqua. La consecuencia es que la funcionalidad comn, por ejemplo las generalizaciones comunes para las subclases, es encontrada en las superclases. La funcionalidad especfica, por ejemplo, la extensin y/o la especializacin, es encontrada en subclases individuales. El ejemplo clsico de una jerarqua de generalizacin es la taxonoma biolgica (p.ej., un gato EsUn mamfero; un mamfero EsUn animal...). Aunque hemos tratado estos tres distintos tipos de subclaseado separadamente, en la prctica son combinados con bastante frecuencia. Es posible y comn para una nica subclase tanto extender a una superclase como especializar un aspecto de la superclase, y para las superclases haber sido identificadas a travs de un proceso de generalizacin.

Especializacin

Generalizacin

Aprendiendo OOP con Delphi

Pgina 17 de 19

Creado el 16/04/09

Sumario del Captulo


Puntos principales: 1. Visual Form Inheritance (VFI): reutilizacin generada va RAD de clases de interfaz de usuario. 2. Visual Component Library (VCL): Generalizacin, herencia para reutilizacin. 3. Reutilizacin: Herencia para extensin, especializacin (a travs de la sobreescritura) y generalizacin.

Objetos como entidades derivadas: Herencia de clase; composicin. Objetos como entidades que interactan: Mensajes simples, visibilidad de otras units y objetos. Diagramas UML: Herencia y asociacin en diagramas de Clases.

Aprendiendo OOP con Delphi

Pgina 18 de 19

Creado el 16/04/09

Problemas
Algunos de los problemas del captulo 3 comprueban principios cubiertos en ste captulo.

Problema 2.1. Estudio del Captulo 2


Identifique los apropiados ejemplos o secciones del captulo para ilustrar cada comentario realizado en el sumario anterior.

Problema 2.2. Usando la Ayuda


El ejemplo 2.2, paso 2, incluye el cdigo:
if Button = btNext then Form1.Top := Form1.Top - 20 else Form1.Top := Form1.Top + 20;

Cul es el significado de btNext? Cmo puede encontrar esto usando la ayuda? Cmo podra recodificar ste estamento If para que la parte del then en su lugar aada 20 y la parte else sustraiga 20 para dar la misma funcionalidad?

Aprendiendo OOP con Delphi

Pgina 19 de 19