Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Encapsulacin
Herencia
Polimorfismo
NOTA: Clases
En .NET siempre usamos una clase para escribir cualquier tipo
de cdigo. Por tanto, hagamos lo que hagamos en .NET
Framework, debemos hacerlo dentro de una clase. Esto no
quiere decir que siempre tengamos que usar las caractersticas
de la POO, ya que si simplemente queremos hacer una
aplicacin que muestre un mensaje en la consola, el cdigo no
tiene porqu usar la herencia, el polimorfismo o la
encapsulacin, simplemente escribimos el cdigo que muestre el
mensaje y asunto arreglado, pero lo que si podremos hacer es
usar algunas de las "otras" ventajas que nos aporta la
programacin orienta a objetos.
INTERFACES
Cuando hablamos de polimorfismo, ineludiblemente tenemos que hablar de las
interfaces, ya que, principalmente, nos posibilita utilizar esta caracterstica de
la POO. La pregunta es: qu es una interfaz? Aqu no hablamos de "interfaces
de usuario", es decir, lo que se mostrar al usuario de nuestra aplicacin, sino
a una clase especial en la que solamente se definen los mtodos y propiedades
que una clase que la implemente debe codificar. Las interfaces representan un
contrato, de forma que cualquier clase que la implemente debe utilizar los
miembros de la interfaz usando la misma forma en que sta la ha descrito:
mismo nmero de argumentos, mismo tipo de datos devuelto, etc.
Gracias a la implementacin de interfaces podemos crear relaciones entre
clases que no estn derivadas de la misma clase base, pero que tengan
mtodos comunes, al menos en la forma, aunque no necesariamente en el
fondo. Anteriormente usamos el ejemplo del mtodo Guardar, este mtodo se
puede definir en una interfaz, las clases que quieran implementar un mtodo
Guardar "estandarizado" firmarn un contrato con la interfaz que lo especifica,
aunque la forma interna de funcionamiento solo atae al programador de la
clase, lo importante es saber que cualquier clase que haya firmado ese
contrato tendr que seguir las condiciones impuestas por la interfaz, de esta
forma todas las clases tendrn un mtodo Guardar "compatible", aunque, tal
como mostramos antes, cmo se realice esa accin de guardar no debe
preocuparnos, simplemente nos fiaremos de que se ha implementado
adecuadamente para almacenar los datos que la clase manipula.
SOBRECARGA (OVERLOAD)
Una de las caractersticas que tambin nos ofrece los lenguajes orientados a
objetos es la posibilidad de definir varias funciones de las clases con un mismo
nombre, de esta forma, podremos crear versiones diferentes, por ejemplo para
que reciban argumentos de distintos tipos sin necesidad de cambiarle el
nombre.
Supongamos que queremos hacer una funcin que realice cualquier tipo de
operacin sobre dos valores numricos, sera lgico pensar que si esos valores
son de tipo entero, el resultado que devuelva la funcin tambin debera ser de
tipo entero, en caso de que los valores a usar en la operacin son de tipo
flotante, el resultado podra devolverlo de ese mismo tipo.
En los lenguajes no orientado a objetos, tendramos que crear dos funciones
con nombres diferentes, por ejemplo: sumaInt y sumaFloat. Pero la
sobrecarga nos permite crear dos funciones que se llamen suma y el
compilador utilizar la adecuada segn el tipo de datos que pasemos como
argumentos.
El nico requisito para poder crear sobrecargas de mtodos es que las
diferentes versiones se diferencien en los argumentos, ya sea porque sean de
diferentes tipos de datos o porque el nmero de argumentos usados sea
diferente, de esa forma el compilador no tendr ningn problema en saber cual
debe usar en cada ocasin. La sobrecarga la podemos aplicar tanto a los
constructores como a cualquier otro mtodo de la clase.
NOTA: Sobrecarga
No existir la posibilidad de crear mtodos sobrecargados si
solamente se diferencian en el tipo de datos devuelto, ya que en
esos casos el compilador no podr decidir correctamente qu
mtodo debe utilizar.
NOTA: Mtodos
En C# los mtodos siempre son funciones, que devolvern un
tipo concreto o el valor especial void, que se usa para indicar
que una funcin no devolver ningn valor.
En Visual Basic .NET existen dos tipos de mtodos distintos, las
funciones (Function) que siempre devuelven un valor y los
procedimientos (Sub) que no devuelven ningn valor.
NOTA: mbito
Los miembros de una clase los podemos declarar sin especificar
el mbito, dependiendo del lenguaje de programacin que
usemos se aplicar un modificador de mbito u otro. En C#, si
no indicamos el mbito, las declaraciones se consideran
privadas, mientras que en Visual Basic .NET el mbito
predeterminado es Friend.
Overridable (virtual). Los miembros virtuales son los que las clases
derivadas puedes sobrescribir para crear su propia versin. Para indicar
en una clase derivada que estamos sobrescribiendo dicho elemento,
usaremos Overrides (override en C#).
NOTA: STATIC
En Visual Basic existe tambin la instruccin Static, (que no
tiene equivalencia en C#), en este caso se utiliza con variables
declaradas en un procedimiento y sirven para indicar que esa
variable debe mantener el valor entre distintas llamadas a dicho
procedimiento, a diferencia del resto de variables que solo
existen mientras se ejecuta el cdigo del procedimiento y cuyos
valores se pierden al finaliza la ejecucin del mismo.
Conclusiones
En la segunda parte de esta serie dedicada a la programacin orientada a
objetos veremos cmo poner en prctica todo lo que hemos comentado,
adems de ver otras peculiaridades de la POO, tales como la definicin de
interfaces y cmo implementarlas, ocasin que tambin aprovecharemos para
ver de forma prctica cmo usar el polimorfismo y la herencia en los lenguajes
de .NET.
Introduccin:
En la entrega anterior vimos algunos conceptos tericos de la POO
(Programacin Orientada a Objetos) desde el punto de vista de los lenguajes
de .NET Framework, en esta ocasin veremos con ejemplos prcticos cmo
utilizar las caractersticas de la POO en Visual Basic .NET, (en el ZIP se incluye
tambin el cdigo para C#), de forma que tengamos claro cmo usar la
herencia, el polimorfismo y la encapsulacin, pero con cdigo.
Nota:
Este artculo se public en Octubre de 2004, y por tanto todo lo
aqu explicado est relacionado con la versin 1.1 de .NET
Framework.
La versin de .NET Framework que hay actualmente (a la hora
de escribir esta nota) es la 3.0, (que en el fondo es la misma
que la 2.0), y se han introducido ciertos cambios o mejoras,
pero bsicamente lo aqu explicado sigue siendo tan vlido
ahora como hace dos aos.
NOTA:
En Visual Basic .NET la definicin de una clase se puede hacer
en cualquier fichero de cdigo (con extensin .vb), aunque no
es obligatorio hacerlo en un fichero independiente como ocurra
con las versiones anteriores, es recomendable hacerlo, para que
nos resulte ms fcil de mantener.
Public Class A
Private _prop2 As Integer
Private _prop1 As String
'
Public Property Prop1() As String
Get
Return _prop1
End Get
Set(ByVal value As String)
If value <> "" Then
_prop1 = value
End If
End Set
End Property
Public Property Prop2() As Integer
Get
Return _prop2
End Get
Set(ByVal value As Integer)
_prop2 = value
End Set
End Property
'
Public Sub Mostrar()
Console.WriteLine("{0}, {1}", _prop1, _prop2)
End Sub
End Class
Listado 1
Tal como podemos ver en el listado 1, tenemos una clase llamada A que define
dos campos, dos propiedades y un mtodo. Los dos campos, declarados como
privados, se usan para mantener "internamente" la informacin que se expone
mediante las dos propiedades pblicas, de esta forma protegemos los datos y
esta sera una forma de encapsular la informacin.
De las dos propiedades definidas para acceder a esos datos, solo la propiedad
Prop1 hace una comprobacin de que no se asigne una cadena vaca al campo
que mantiene internamente la informacin, aunque en este ejemplo por su
simplicidad no hacemos ms comprobaciones, en una clase algo ms compleja,
se podran realizar otras comprobaciones, por ejemplo si el valor a almacenar
es una cuenta de email, podramos comprobar que es una cadena
correctamente formada.
Las propiedades suelen definir dos bloques de cdigo, uno, el bloque Get se
utiliza cuando queremos acceder al valor devuelto por la propiedad, el otro es
el bloque Set, el cual se utilizar cuando asignemos un valor a la propiedad.
El mtodo Mostrar se usar para mostrar el contenido de las dos propiedades
por la consola y est definido como Sub (void en C#) porque no devuelve
ningn valor.
Sub Main()
Dim objB As New B
objB.Prop1 = "guille"
objB.Prop2 = 47
objB.Mostrar()
Console.WriteLine("{0}", objB.ToString)
End Sub
Listado 2
Esa advertencia nos informa que deberamos indicar que la declaracin "oculta"
a la definida en la clase A y por tanto deberamos usar la instruccin Shadows
(new en C#). Aunque usemos Shadows, el problema real sigue existiendo: el
mtodo declarado en la clase B oculta al declarado (y heredado) en la clase A.
Si despus de definir este mtodo de la clase B volvemos a ejecutar el cdigo
del listado 2, comprobaremos que se utiliza el nuevo mtodo.
Posiblemente el lector pensar que eso es lo que queramos conseguir: tener
nuestra propia versin del mtodo Mostrar. Es ms, si definimos una nueva
clase que se derive de B podemos comprobar que realmente es ese mtodo el
que
se
hereda
por
la
nueva
clase.
En el listado 3 podemos ver la definicin de la clase C y el cdigo para
comprobar lo que mostrara:
Public Class C
Inherits B
End Class
Sub Main()
Dim objC As New C
objC.Prop1 = "guille"
objC.Prop2 = 47
objC.Mostrar()
Console.WriteLine("{0}", objC.ToString)
End Sub
Listado 3
NOTA:
Cuando declaramos una variable y la instanciamos, (creando un
nuevo objeto a partir de una clase), dicha variable simplemente
tiene una referencia al objeto creado en la memoria, (la variable
simplemente tiene un puntero al objeto real), por tanto, ese
objeto existe y puede ser referenciado por otras variables,
aunque esas otras variables deben ser de tipos "incluidos" en la
clase usada para crear dicho objeto.
Al instanciar un nuevo objeto del tipo B, (tal como se muestra
en la figura 2), podemos acceder a l mediante variables de tipo
Object, de tipo A y, por supuesto, de tipo B.
DEFINIENDO INTERFACES
Una interfaz realmente es la definicin de los miembros pblicos de una clase.
Pero en los lenguajes de programacin de .NET tambin podemos definir clases
especiales que simplemente definan cmo deben ser los miembros que una
clase implemente. Es decir que caractersticas deben tener. De esta forma
podemos garantizar que si varias clases implementan los miembros definidos
en una interfaz, podemos usarlos de manera annima, es decir, sin necesidad
de saber si estamos usando un objeto de una clase o de otra, ya que si ambas
clases implementan la interfaz, tendremos la certeza de que dichas clases
tienen los miembros definidos en dicha interfaz.
Una interfaz representa un contrato, si una clase implementa una interfaz, est
suscribiendo dicho contrato, es ms, est obligada a cumplirlo, por tanto, la
clase tendr que definir todos los miembros que la interfaz contenga.
Antes de ver cmo usar las interfaces en nuestras clases, veamos cmo definir
una interfaz.
Public Interface IPrueba2
Property Prop1() As String
Sub Mostrar()
End Interface
En este caso hemos definido una interfaz llamada IPrueba2 (por convencin
los nombres de las interfaces siempre empiezan con la letra I mayscula), en
la
que
se
define
una
propiedad
y
un
mtodo.
Los miembros de las interfaces siempre son pblicos y no deben implementar
cdigo, solamente la definicin propiamente dicha.
Listado 4
i.Mostrar()
Listado 5
Una de las utilidades del polimorfismo (de clases o interfaces) es que podemos
crear arrays de variables de un tipo "bsico" y en ese array incluir objetos que
si bien son distintos, en el fondo tienen como parte componente la clase de la
que
se
ha
declarado
el
array.
El ejemplo ms bsico y vlido tanto para las clases declaradas en el propio
.NET Framework como las declaradas por nosotros mismos, es crear un array
de tipo Object, dicho array podr contener objetos de cualquier tipo (incluso
tipos como nmeros enteros, cadenas, etc.), y posteriormente poder acceder a
cualquiera de los elementos mediante un objeto del tipo Object, en cuyo caso
solo podremos acceder a los mtodos que Object implementa o bien mediante
objetos de un tipo en particular, en cuyo caso nos veremos obligados a hacer
una conversin desde el tipo contenido en el array (Object) al tipo particular
que nos interese.
En el listado 6 podemos ver un ejemplo en el que se crea un array de tipo
Object pero que se almacenan tanto objetos del tipo clase A, clase B,
IPrueba2, Integer y String.
Console.WriteLine()
'
Console.WriteLine("Usando un Object")
Dim o As Object
For Each o In a
Console.WriteLine("o.ToString = {0}", o.ToString())
Next
'
Console.WriteLine()
'
Console.WriteLine("Usando tipos especficos")
For Each o In a
Console.WriteLine("El tipo es: {0}", o.GetType().Name)
If TypeOf o Is A Then
Dim tA As A = CType(o, A)
tA.Mostrar()
ElseIf TypeOf o Is IPrueba2 Then
Dim tIPrueba2 As IPrueba2 = CType(o, IPrueba2)
tIPrueba2.Mostrar()
ElseIf TypeOf o Is Integer Then
Dim tInt As Integer = CType(o, Integer)
Console.WriteLine(tInt.ToString("00000"))
ElseIf TypeOf o Is String Then
Dim tStr As String = o.ToString
Console.WriteLine(tStr)
Else
Console.WriteLine("o.ToString = {0}", o.ToString())
End If
Next
Listado 6
Nota:
Por la extensin del listado, el mismo se incluye en el ZIP con el
cdigo de los ejemplos (tanto para Visual Basic como para C#),
en el listado 7 puedes ver cmo usar esas clases.
S mostrar el saldo
Sub Main()
Dim acli(6) As Cliente
'
acli(0) = New Cliente("Jose", "Sanchez", 125.5D)
acli(1) = New ClienteOro("Luis", "Rebelde", 2500.75D)
Listado 7
End Sub
Public Sub New( _
ByVal elNombre As String, _
ByVal losApellidos As String, _
ByVal elSaldo As Decimal)
_nombre = elNombre
_apellidos = losApellidos
_saldo = elSaldo
End Sub
Listado 8
En estos casos, en Visual Basic es fcil hacerlo, como sabemos que los
constructores realmente son mtodos llamados New, los podemos usar de la
misma forma que haramos con cualquier otro mtodo.
Por ejemplo, si modificamos el cdigo mostrado en el listado 8, podramos
hacer esto:
Public Sub New( _
ByVal elNombre As String, _
ByVal losApellidos As String, _
ByVal elSaldo As Decimal)
Me.New(elNombre, losApellidos)
_saldo = elSaldo
End Sub
De forma que desde el constructor que recibe tres parmetros llamemos al que
recibe dos.
En este caso, la instruccin o palabra clave Me representa a la instancia actual
(el
objeto
que
se
ha
creado
en
memoria).
Si en lugar de llamar a otro constructor de la propia clase, queremos llamar a
un constructor de la clase base, en lugar de Me, usaremos MyBase.
En C# este mismo cdigo se hara de la siguiente forma:
public Cliente(string elNombre,
string losApellidos,
decimal elSaldo)
: this(elNombre, losApellidos)
{
_saldo = elSaldo;
}
CLASES ABSTRACTAS
MIEMBROS ABSTRACTOS
Cuando comentamos que las clases abstractas son como las interfaces no solo
nos referamos a que se podran usar para proporcionar polimorfismo, sino
Conclusiones
Confo que todo el tema tratado sobre la programacin orientada a objetos, y
por extensin a la herencia, desde el punto de vista de un programador de
.NET Framework nos permita afrontar todo este tema, que si bien al principio
puede parecer algo "escabroso", realmente debera ser una forma natural de
programar, sobre todo si tenemos en cuenta que todo el .NET Framework se
basa en las clases, interfaces y dems conceptos relacionados con la POO.
Nos vemos.
Guillermo
Nota:
Los proyectos estn creados con Visual Studio .NET 2003 pero
se pueden usar en cualquier versin de Visual Studio 2005,
incluso las versiones Express, aunque en este ltimo caso,
tendrs que cargar de forma independiente los proyectos de
Visual Basic o de Visual C#.