Crear e implementar una
interfaz
Como se ha explicado en "Cómo proporciona Visual Basic el polimorfismo", una
interfaz es un conjunto de propiedades y métodos. En el siguiente ejemplo de
código se creará una interfaz Animal y se implementará en dos clases, Pulga y
Tiranosaurio.
Puede crear la interfaz Animal si agrega un módulo de clase al proyecto, le
asigna el nombre Animal e inserta el código siguiente:
Public Sub Mover(ByVal Distance As Double)
End Sub
Public Sub Morder(ByVal What As Object)
End Sub
Observe que estos métodos no contienen código. Animal es una
clase
abstracta, que no contiene código de implementación. El propósito de una
clase abstracta no es crear objetos, sino proporcionar una plantilla de interfaz
que puede agregar a otras clases. No obstante, como verá, algunas veces resulta
útil implementar la interfaz de una clase no abstracta; esto se describe más
adelante en este tema.
Nota Hablando con propiedad, una
clase abstracta es una clase a partir de la cual no puede crear objetos. Siempre
puede crear objetos a partir de clases de Visual Basic, incluso aunque no
contengan código; así que no se pueden considerar realmente abstractas.
Ahora puede agregar dos módulos de clase más. Asigne a uno de ellos el nombre
Pulga y al otro Tiranosaurio. Para implementar la interfaz Animal en la clase
Pulga, utilice la instrucción
Implements:
Option Explicit
Implements Animal
En cuanto agregue esta línea de código, puede hacer clic en la lista
desplegable (
Objeto) de la izquierda de la ventana
Código. Una de
las entradas será Animal. Cuando la seleccione, la lista desplegable
(
Procedimiento) de la derecha mostrará los métodos de la interfaz
Animal.
Seleccione los métodos de uno en uno para crear plantillas de procedimiento
vacías en todos los métodos. Las plantillas tendrán los argumentos y los tipos
de datos correctos, como se han definido en la clase Animal. Cada nombre de
procedimiento tendrá el prefijo
Animal_ para identificar la interfaz.
Importante Una interfaz es como
un contrato. Al implementar la interfaz, una clase se compromete a responder
cuando se invoque cualquier propiedad o método de la interfaz. Por tanto, debe
implementar
todas las propiedades y los métodos de una interfaz.
Ahora puede agregar el código siguiente a la clase Pulga:
Private Sub Animal_Mover(ByVal Distance As Double)
' (Se omite el código del salto.)
Debug.Print "Pulga movida"
End Sub
Private Sub Animal_Morder(ByVal What As Object)
' (Se omite el código del picotazo.)
Debug.Print "La pulga mordió un " & TypeName(What)
End Sub
Puede que se pregunte por qué los procedimientos se declaran
Private.
Si fueran
Public, los procedimientos Animal_Mover y Animal_Morder
formarían parte de la interfaz Pulga y tendría el mismo enlace original, al
declarar el argumento Critter
As Object para que pueda contener una Pulga
o un Tiranosaurio.
Interfaces múltiplesLa clase Pulga tiene ahora dos interfaces: la interfaz Animal recién
implementada, que tiene dos miembros, y la interfaz Pulga predeterminada, que no
tiene miembros. Más adelante en este ejemplo se agregará un miembro a una de las
interfaces predeterminadas.
Puede implementar la interfaz Animal de forma similar para la clase
Tiranosaurio:
Option Explicit
Implements Animal
Private Sub Animal_Mover(ByVal Distance As Double)
' (Se omite el código de la zancada.)
Debug.Print "Tiranosaurio movido"
End Sub
Private Sub Animal_Morder(ByVal What As Object)
' (Se omite el código de la dentellada.)
Debug.Print "El Tiranosaurio ha mordido un " & TypeName(What)
End Sub
Pruebas con el Tiranosaurio y la PulgaAgregue el código siguiente al evento Load de Form1:
Private Sub Form_Load()
Dim fl As Pulga
Dim ty As Tiranosaurio
Dim anim As Animal
Set fl = New Pulga
Set ty = New Tiranosaurio
' Primero le toca a la pulga.
Set anim = fl
Call anim.Morder(ty) ' La pulga muerde al
' dinosaurio.
' Ahora es el turno del Tiranosaurio.
Set anim = ty
Call anim.Morder(fl) ' El dinosaurio muerde a
' la pulga.
End Sub
Presione F8 para recorrer el código. Observe los mensajes de la ventana
Inmediato. Cuando la variable
contiene una referencia a Pulga,
se invoca la implementación de Morder de Pulga y de la misma forma para
Tiranosaurio.
La variable
puede contener una referencia a cualquier
objeto que implemente la interfaz Animal. De hecho,
sólo puede contener
referencias a dichos objetos. Si intenta asignar un objeto
Form o
PictureBox a
, se producirá un error.
El método Morder se enlaza en tiempo de diseño cuando lo llama mediante
, puesto que Visual Basic sabe en tiempo de compilación que
cualquier objeto asignado a
tendrá un método Morder.
<H4>Paso de Tiranosaurios y Pulgas a procedimientos</H4>
Recuerde el procedimiento GetFood (Alimentarse) de "¿Cómo proporciona Visual
Basic el polimorfismo?". Puede agregar la
segunda versión del
procedimiento GetFood (el que ilustra el polimorfismo) a Form1 y sustituir el
código del evento Load por el siguiente:
Private Sub Form_Load()
Dim fl As Pulga
Dim ty As Tiranosaurio
Set fl = New Pulga
Set ty = New Tiranosaurio
'La pulga se come al dinosaurio.
Call GetFood(fl, ty)
' Y viceversa.
Call GetFood(ty, fl)
End Sub
El repaso de este código muestra cómo una referencia de objeto pasada a un
argumento de otro tipo de interfaz se convierte en referencia a la segunda
interfaz (en este caso, Animal). Lo que ocurre es que Visual Basic consulta el
objeto para saber si acepta la segunda interfaz. Si el objeto lo acepta,
devuelve una referencia a la interfaz y Visual Basic coloca esa referencia en la
variable del argumento. Si el objeto no acepta la segunda interfaz, se produce
un error.
Implementar métodos que devuelven valoresSuponga que el método Mover devolviera un valor. Después de todo, sabe cuánto
quiere que se mueva el Animal, pero un espécimen concreto podría no ser capaz de
llegar tan lejos. Podría estar viejo y decrépito o podría haber un muro en su
camino. Puede usar el valor devuelto por el método Mover para saber indicarle el
movimiento real del Animal.
Public Function Mover(ByVal Distance As Double) _
As Double
End Function
Cuando implemente este método en la clase Tiranosaurio, asigne el valor
devuelto al nombre del procedimiento, como lo haría en cualquier otro
procedimiento
Function:
Private Function Animal_Mover(ByVal Distance _
As Double) As Double
Dim dblDistanceMoved As Double
' Código para calcular la distancia (basado en
' edad, salud y obstáculos) omitido.
' Este ejemplo asume que el resultado se encuentra
' en la variable dblDistanceMoved.
Debug.Print "Tiranosaurio movido ";
dblDistanceMoved
Animal_Mover = dblDistanceMoved
End Function
Para asignar el valor devuelto, utilice el nombre completo del procedimiento,
incluido el prefijo de la interfaz.