Programación Orientada a Objetos con Visual Basic .NET
Parte III
Por Willy Mejía [WillyXoft]
Heredando
La Herencia es una de las características más importantes en la POO porque
permite que una clase herede los atributos y métodos de otra clase, lo que
garantiza la reutilización de código.
Con la herencia todas las clases están
clasificadas según una jerarquía. Cada clase tiene una clase base o superclase,
ésto es de jerarquía superior, y puede tener una o más clases derivadas o
subclases, de inferior jerarquía. Las clases que están en la parte inferior de
una jerarquía heredan de las clases que están en la parte superior de su
jerarquía.
La herencia implica que las subclases disponen de todos los miembros
públicos (métodos y propiedades) de su superclase. Lo cual permite extender la
funcionalidad de una clase añadiendo sus propios atributos y métodos o incluso
alterando el comportamiento heredado. De este modo se pueden crear objetos
especializados en base a otros, tal y como se observa en la vida real.
La herencia hace posible la reutilizacion de componentes, que es una de las
principales razones para utilizar el paradigma de la POO, la otra es que facilita el
entendimiento (legibilidad) y mantenimiento del código implementado.
Con la Herencia puede
definir una clase común como la clase base o madre (o padre según lo prefiera)
para otras clases
llamadas clases derivadas o hijas, las cuales serían versiones especializadas
de la primera. A su vez, los miembros heredados por una clase derivada pueden
ser heredados por más clases hijas de ella, propagando la herencia.
Por ejemplo, toda clase en el .NET Framework es una subclase de la clase base
llamada System.Object, de la cual heredan sus propiedades y métodos públicos,
entre ellos el el método ToString(). De modo que si creamos una clase llamada
Cliente la cual no declare ni implemente método alguno, aún así podríamos
invocar el método ToString():
Class Cliente
End Class
Cliente.ToString()
No obstante podemos sobre-escribir el comportamiento de dicho metodo
utilizando la palabra clave Overrides:
Public Overrides Function ToString() As String
Return mNombre
End Public
Esta operación se puede realizar con cualquier método heredado, siempre y cuando el
método de la clase base lo permita por medio de la palabra clave Overridable.
Pero ésto lo abodaremos más adelante en Polimorfismo.
Para poder definir la herencia directa hacia una clase en particular se utiliza la
palabra clave Inherits. De modo que teniendo una clase (A) podemos
escribir otra clase (B) que herede su implementación de la siguiente manera:
Class A
End Class
Class B
Inherits A
End Class
Así por ejemplo, para crear una clase que herede de Cliente, escribimos:
Public Class ClienteFrecuente
Inherits Cliente
Public Sub New()
MyBase.New()
End Sub
' Implementación especializada de la clase...
End Class
El constructor de una clase Derivada llama de manera implícita al constructor
de su clase Base. Pero se puede utilizar la palabra clave MyBase para invocar
cualquier miembro público de la clase Base, en éste caso al constructor de
la clase base Cliente, de manera explícita.
Por otro lado, puede utilizar la palabra clave MyClass permite llamar
a un método remplazable (Overridable) implementado en la clase y asegurarse de
que se llama a la implementación del método en esta clase y no a la de un método
reemplazado en una clase derivada. Para un mayor entendimiento vuelva a leer
este párrafo después de leer sobre Polimorfismo más adelante.
Cuando utilizar la herencia
Puede realizar herencia de clases jerarquizada según la necesidad de especialización
requerida, no obstante se recomienda no ir mas alla de cuatro niveles. Por otro
lado debe tener claro cuando no utilizar Herencia.
Los principales
usos de la Herencia son cuando:
- Tiene objetos de diferentes tipos con funcionalidad similar.
- Tiene un conjunto de procesamientos a ser realizados por un conjunto de objetos.
Pero no debería utilizar Herencia cuando:
- Sólo necesite una función de la clase base en su clase.
- Si necesita sobre-escribir todos los métodos de la clase base -en ese
caso mejor emplee Interfaces (ver más adelante).
- La semantica de la herencia (o relación) entre clases no es muy clara.
El .NET Framework sólo permite la herencia simple entre clases, es decir
que una clase Derivada sólo puede tener una sóla clase Base, pero si permite la
herencia múltiple de Interfaces por medio de la implementación obligatoria de
los miembros declarados en las Interfaces.
Una Interfaz es un tipo especial parecido una Clase, con la salvedad
que sólo declara miembros públicos pero sin implementar código dentro de los
mismos. Por lo que lo único que hereda es la obligación de implementar el código
de dichos mimbros.
Para heredar la declaración de los miembros de una Interface se emplea la
palabra clave Implement.
Interface IEjemplo
Sub PorImplemetar()
End Interface
Class Implementadora
Inherits ClaseBase
Implements IEjemplo
Public Sub PorImplementar() Implements IEjemplo.PorImplementar
' Código de implementación...
End Sub
End Class
Dado que las Interfaces no heredan implementación de código, pocos ven la
ventaja de utilizarlas. No obstante son muy útiles por diversas razones entre
las cuales podemos citar la especificación de métodos y propiedades bajo
contrato, de manera que estarémos seguros que todas las clases derivadas
contarán con algúnos métodos o propiedades que pueden ser invocados con
seguridad.
Para mayor información léa:
Cuándo utilizar la herencia.
Encapsulando
La Encapsulacion es "referenciada" como el ocultamiento de datos.
Para limplementarla utilizamos modificadores de acceso que son palabras clave
que se utilizan para declarar o especificar el nivel de accesibilidad o
"visibilidad" que tiene un miembro o un tipo. Cuando se permite el acceso a un miembro,
se dice que éste es accesible o visible. De lo contrario, es inaccesible u
oculto.
En VB.NET se manejan cuatro modificadores de acceso y cinco niveles de
accesibilidad. Los modificadores de acceso son: Private, Protected,
Friend y Public, mientras que los niveles de accesibilidad, del
más al menos restrictivo, són:
- Private: Corresponde al nivel de acceso más restrictivo. Los
miembros privados sólo son accesibles dentro del cuerpo de la clase o la
estructura en la cual se declaran.
- Protected: Los miembros protegidos son accesible desde dentro de
la clase en la que se ha declarado, y desde dentro de cualquier clase
derivada de la clase que declaró este miembro. Una clase derivada puede
obtener acceso a un miembro Protected, siempre que el miembro no sea un
miembro de una instancia o el acceso se realice a través de una instancia de
la clase derivada.
Nota: Este tipo de accesibilidad no puede ser utilizado en estructuras.
- Friend: Los miembros de tipo "amigo" o interno sólo son
accesibles dentro de archivos del mismo ensamblado. Desde el punto del IDE
se dice que su accesibilidad es a nivel de proyecto, ya que por cada
proyecto se genera un sólo ensamblado.
- Protected Friend: Es una combinación de los dos anteriores, por
lo que el acceso está limitado al proyecto actual o a los tipos derivados de
la clase.
Nota: Es la única combinación de modificadores de acceso permitida y no
puede ser utilizada en estructuras.
- Public: Corresponde al nivel de acceso menos restrictivo. No
existen restricciones en el acceso a miembros públicos.
Los niveles de acceso privado (Private) y protegido (Protected) aseguran la encapsulación,
ya que ocultan o hacen inccesibles a los miembros desde el exterior de la clase.
Por ello los campos (variables) son declarados con éstos modificadores de
acceso, mientras los miembros que alteran su valor: propiedades, procedimientos
y funciones, son declarados como públicos (Public).
El uso habitual del acceso de tipo Friend (y Protected-Friend) se da en
el desarrollo basado en componentes, ya que permite a un grupo de componentes
el cooperar de manera privada sin estar expuesto al resto de la
aplicación.
Si no se especifica ningún modificador de acceso en una declaración de
miembro, se utiliza el nivel de acceso predeterminado para el tipo de miembro. El
nivel de acceso predeterminados
para las variables es Private, mientras que para las propiedades, procedimientos y
funciones es Public. No obstante es altamente recomendable el siempre especificar
de manera explícita el nivel de acceso de los diferentes miembros.

Veamos un ejemplo:
'Project One
Class A
Private i As Integer
Protected l As Integer
Friend j As Integer
Protected Friend m As Integer
Public k As Integer
End Class
Class B
'Puede acceder a: j,k,m
End Class
Class C
Inherits A 'Derivada de A
'Puede acceder a: j,k,l,m
End Class
'Project Y
Class D
Inherits A 'Derivada de A
'Puede acceder a: k,l,m
Class E
'Sólo puede acceder a k
End Class
Polimorfismo
El polimorfismo proporciona la capacidad de variar la implementación de un
método remplazable (o sobre-escribible), de modo que el mismo método base puede
realizar diferentes acciones, dependiendo de la instancia que invoque el método
en tiempo de ejecución. En VB6 se empleaban las interfaces, mismas que aún
pueden seguir utilizándose en Visual Basic .NET. Mas ahora también podemos
implementar el Polimorfismo mediante Herencia, para ello el método remplazable
en la clase Base deberá estar calificado con la palabra clave Overridable,
y el método que lo remplaza en la clase derivada deberá estar calificado con la
palabra clave Overrides
Public Class Animal
Public Overridable Sub Comer(ByVal a As Alimento)
Console.WriteLine("Come " & a.ToString)
End Sub
'...
End Class
Public Class Carnivoro
Inherits Animal
Public Overrides Sub Comer(ByVal a As Alimento)
If Alimento.Type.ToString = "Carne" Then
MyBase.Comer(a)
Me.Calorias += a.Peso * 100
Else
Me.Regurgitar
End If
End Sub
'...
End Class
Public Class Herbivoro
Inherits Animal
Public Overrides Sub Comer(ByVal a As Alimento)
If Alimento.Type.ToString = "Vegetal" Then
MyBase.Comer(a)
Me.Calorias += a.Peso * 20
Else If
Me.Regurgitar
End If
End Sub
'...
End Class
'ToDo: Omnívoro
Si no se utiliza la palabra clave Overrides al intentar remplazar un método, en lugar de
"sobre-escribirlo" sólo se está "ensombreciendo" al mismo.
Lo cual es la única opción si el método de la clase base no especifica que es
remplazable, mas sin embargo debe entonces calificar el metodo "sombra" con la
palabra clave Shadows u Overloads, de lo contrario se recibirá una
advertencia. Por otro lado Overloads se utiliza cuando se desea cambiar
la lista de argumentos del método a "ensombrecer".
Un método reemplazable también puede ser calificado con la palabra clave MustOverride, lo que
significa que no proporciona ningún cuerpo de método y que debe ser reemplazado,
por ello no puede incluir los modificadores Shared u Overridable.
Los métodos MustOverride sólo se permiten en las "clases selladas" las
cuales se califican con la palabra clave MustInherit:
En el ejemplo siguiente, la clase Shape define la
noción abstracta de un objeto de forma geométrica que puede dibujarse él mismo:
MustInherit Public Class Shape
Public MustOverride Sub Paint(g As Graphics, r As Rectangle)
End Class
Public Class Ellipse
Inherits Shape
Public Overrides Sub Paint(g As Graphics, r As Rectangle)
g.drawEllipse(r)
End Sub
End Class
Public Class Box
Inherits Shape
Public Overrides Sub Paint(g As Graphics, r As Rectangle)
g.drawRect(r)
End Sub
End Class
El método Paint es MustOverride porque no
existe una implementación predeterminada significativa. Las clases
Ellipse y Box son
implementaciones Shape concretas. Dado que estas clases
no son MustInherit, son necesarias para reemplazar el método
Paint y proporcionar una implementación real.
Conclusión
Hasta aquí hemos terminado ésta serie en donde hemos realizado un breve
recorrido a los principales conceptos que enmarcan a la Programación Orientada a
Objetos así como su aplicación con el lenguaje de programación Visual Basic
.NET. Espero que con esto el lector que no conocía a la misma, así como aquel
que sólo tenía una idea, hayan resuelto sus dudas y perdido el miedo a este tipo
de programación para de ahora en adelante aprovechar los beneficios de la misma
con el renovado lenguaje de programación Visual Basic .NET 100% Orientado
Objetos.
Si bien existen muchos otros conceptos y técnicas surgidos a partir de la
práctica de la POO, los mismos que no fueron parte del objetivo de la serie,
pero trataré de abordarlos en siguientes ocasiones. Así que hasta la próxima.
Continuar con POO con Visual Basic .NET Parte 1