Introducción
Un interfaz proporciona una lista de propiedades y
métodos que posteriormente serán codificados en una o varias clases. Es decir,
su naturaleza es declarativa, no contiene código de los miembros que expresa. En.
NET, las interfaces se utilizan comúnmente para prestación de servicios para
una clase. La interfaz apoya algo que puede
hacer el objeto de la clase, pero el servicio no está incluido en la relación
es-un de la herencia.
Cuando utilizamos la herencia para hacer nuevas clases diferentes de las clases
existentes, si las clases están relacionadas por la herencia, se puede hacer
referencia a una instancia derivada a través de una referencia a un valor de la
clase base. Este comportamiento polimórfico no se limita a las clases
derivadas. Visual Basic. NET ofrece otra construcción: la interfaz, que también se comporta de forma polimórfica
¿Por qué usar interfaces?
Las interfaces complementan a las clases. No
hay porque pensar en que si se usan interfaces ya no se deben usar clases o
viceversa. Los interfaces nos permiten
definir conjuntos reducidos de funcionalidades. El mismo interfaz implementado
en distintas clases, puede tener un código distinto, por tanto con objetos de
diferentes clases que implementen un mismo interfaz pueden tener
comportamientos diferentes.
La
principal utilidad de las interfaces se muestra en el siguiente ejemplo:
Necesitamos en nuestro programa modelar dos tipos de objetos de la vida real, unos serían los contratos de costo y otros serían contratos de venta. Para eso utilizo una clase para cada uno. Pero como los dos tipos de contrato tienen muchos elementos comunes, entonces hago una clase "padre" llamada Contrato donde defino esos métodos y propiedades comunes y después hago dos clases "hijas" que heredan de Contrato, que son "ContratoVenta" y "ContratoCosto". Hasta ahí todo bien, es un ejemplo muy sencillo de herencia.
Si en algún lugar de nuestro programa (un procedimiento) necesitamos realizar una operación con un contrato y esa operación la hacen tanto los contratos de venta, como de costo, entonces en lugar de escribir código para manejar un contrato de venta y código para manejar un contrato de costo, escribimos el código una sola vez y le pasamos una variable de tipo Contrato (la clase padre). De esa forma, el código que ejecuta la operación no sabe (ni le importa) si está tratando con un contrato de costo o uno de venta, al fin y al cabo la operación que se necesita hacer está definida en la clase padre y eso es todo lo necesario.
Ahora, hay tipos de objetos que no están tan relacionados entre sí como para que se justifique que hereden de una clase común. Sin embargo ambos tipos de objeto si tienen métodos o propiedades que son comunes o simplemente se llaman igual, aunque la implementación de
cada uno de ellos sea distinta.
Para poner un ejemplo fácil, tenemos una clase llamada ContratoVenta y otra clase llamada Factura. Esas dos clases tienen un método Imprimir que imprime su información y podíamos tener una rutina que reciba un objeto de cualquiera de estos dos tipos e imprima su información, invocando el método Imprimir. Esa rutina sabe que el objeto que le envían por parámetros tiene un método que se llama Imprimir y es el que realiza todo el trabajo. Sin embargo hay un problema: ¿de qué tipo es el objeto que le pasamos como parámetro a la rutina?
Pudiera ser:
Public Sub Imprimir (Objeto as Object)
Objeto.Imprimir
End Sub
Pero abusar del tipo Object es malo porque entre otras cosas consume muchos recursos de máquina. Otra idea sería hacer que las dos clases hereden de una común (como en el primer ejemplo), pero en este caso no es buena idea, ya que no hay relación entre ellas como para eso.
La solución es crear una Interfaz, que pudiera llamarse IObjetoImprimible y cuenta con un método Imprimir. Esta interfaz la usan los objetos de tipo Contrato y los de tipo Factura y al final la rutina de impresión puede recibir un ObjetoImprimible:
Public Sub Imprimir (Objeto as ObjetoImprimible)
Objeto.Imprimir
End Sub
Objeto.Imprimir
End Sub
Si por ejemplo, tenemos una interfaz que se
llama Ianimal. Esta publica dos métodos que son Caminar y Respirar. Derivamos
una clase que se llama Perro, que hereda directamente de Ianimal y esta, también
hereda los métodos. Estos no contendrán implementación, entonces puedes implementar
(meter el código) para que el perro pueda caminar y respirar.
Por si misma, la interfaz no contiene código; contiene la estructura necesaria para crear clases de un tipo definido.
Por si misma, la interfaz no contiene código; contiene la estructura necesaria para crear clases de un tipo definido.
¿Es factible dejar de lado el concepto de clases
y comenzar a utilizar las Interfaces en su lugar?
Pues no, no son equivalentes. Una interfaz, es una declaración nada más. Es un
'contrato' que se firma entre el desarrollador que la escribe y el
desarrollador que la usa, donde el primero te dice que si una clase implementa
esa interface entonces contendrá esos métodos tal y como están definidos; el
que usa la interface (para implementarla en una clase) se compromete a
implementar todos y cada uno de los métodos declarados en la misma, tal cual
como están definidos. Define el 'que' se puede hacer, dejando el 'como' hacerlo
para cuando lo implementes en una clase. Y esa es la relación entre los dos
conceptos: las interfaces se deben implementar en clases. Esto significa que en
la clase escribes el código que implementa la funcionalidad de la interfaz. La
interfaz es solamente la declaración, en la clase está el código real. En una
clase puedes implementar más de una interfaz.
El
Interfaz IMover.
Una interfaz es como una clase abstracta con todos los
miembros abstractos. La interfaz sirve como un contrato que define qué métodos,
propiedades y eventos de una clase debe implementar. En este documento, vamos a
crear una interfaz, implementarlo en una clase, y utilizar la clase polimórficamente
a través de una referencia de la interfaz.
La primera tarea es crear una interfaz IMover implementarla en la clase CPeon de nuestro programa de ajedrez, este interfaz puede ser útil si se están moviendo objetos a su alrededor como parte del juego. Las clases en el proyecto pueden ser tan diferentes que no están relacionadas por la herencia, pero que tienen en común la capacidad de ser movidas. La interfaz IMover proporciona un interfaz estándar para el traslado de objetos. Esta interfaz se describe en el siguiente diagrama UML:
Este diagrama presenta un nuevo elemento UML: Una
interfaz. Una propiedad se localiza en la sección de atributos en un elemento
de clase, pero esta correspondencia desaparece en el caso de un elemento de la
interfaz porque el elemento interfaz, tal como se define por el UML, no tiene
una sección atributo. Como las interfaces no soportan implementación, no tienen
datos de la instancia sino métodos solamente. Así pues, si necesitamos encajar
el concepto de propiedad en la interfaz de UML, Los “captadores” get y “definidores”
set se mostrarán como si fueran métodos Get y Set. La
interfaz de IMover contiene dos propiedades, X e Y, y un
método mover que toma dos parámetros de dirección (arriba, abajo, izquierda,
derecha) y la distancia.
El siguiente representa la interfaz en UML. Este estilo se utiliza con más frecuencia que la versión extendida mostrada anteriormente.
El siguiente representa la interfaz en UML. Este estilo se utiliza con más frecuencia que la versión extendida mostrada anteriormente.
En una
empresa genérica sería muy interesante crear un interfaz IMantenimiento que
contenga los métodos Alta, Baja y Modificación que sirvan para cualquier objeto
del programa.
Así mismo
son interesantes los interfaces para imprimir cualquier documento o para el
acceso a la base de datos.
Definir
el interfaz IMover.
Este ejemplo
es una aplicación de consola en lugar de una aplicación de Windows. La salida
del programa aparece en la ventana de comandos. La interfaz define la ubicación
del objeto como propiedades X e Y e incluye un método Mover para mover el objeto alrededor.
1. Creamos un Nuevo
proyecto de tipo Console Application.
2. En el menú de proyecto,
elegimos Add New Item. Y elegimos Code File y lo llamamos IMover.
3. Añadimos el siguiente
código al interfaz IMover interface.
Public Interface IMover
End Interface
4. Añadir una enumeración
para indicar la dirección de movimiento del objeto. Añadir esta enumeración
justo antes del interface.
Public Enum Direccion
Arriba
Abajo
Derecha
Izquierda
End Enum
5. Añadir
dos declaraciones de propiedades en la definición del interfaz. La palabra
clave public no está permitida en la
definición de un interfaz. El propósito de un interfaz es definir los métodos propiedades y eventos que deberá
soportar una clase. Los miembros privados no tienen cabida en este contexto, la
definición de Visual Basic permite los modificadores Readonly y Writeonly de las
propiedades.
Public Interface IMover
Property X() As Integer
Property Y() As Integer
End Interface
6. Añadir la declaración Mover al interfaz.
Sub Mover(ByVal aDirection As
Direccion, ByVal Distancia As Integer)
El interfaz está completo,
para poder utilizarlo, es necesario implementar en interfaz en una clase.
Implementar
el interfaz IMover en la clase CPeon.
Implementaremos las propiedades
X e Y y el método Mover en la clase CPeon
Public Class CPeon
Implements IMover
End Class
Visual Basic usa la
palabra clave Implements para indicar e el interfaz de una
clase.
Notar que
después de escribir Implements, Intellisense despliega una lista de interfaces con un icono
similar al esquema de UML.
Al pulsar
dentro de la clase, se escriben automáticamente los esquemas de las propiedades
y el método que hay definidos en el interfaz IMover.
Public Sub Mover(ByVal
aDirection As Direccion, ByVal Distancia As Integer) Implements
IMover.Mover
End Sub
Public Property X() As Integer Implements Interfaz.IMover.X
Get
End Get
Set(ByVal value As Integer)
End Set
End Property
Public Property Y() As Integer Implements Interfaz.IMover.Y
Get
End Get
Set(ByVal value As Integer)
End Set
End Property
Añadir
un campo a la propiedad X e implementarla.
Public Property X() As Integer Implements Interfaz.IMover.X
Get
Return m_x
End Get
Set(ByVal value As Integer)
m_x = value
End Set
End Property
No se puede utilizar Overrides cuando se están implementando miembros del interfaz.
La interfaz es estrictamente un contrato sobre lo que se encuentra en la
interfaz de clase.
Hay que tener en cuenta que se utiliza la palabra
clave Implements de nuevo
para especificar qué miembro de la interfaz está siendo implementado. La
palabra clave Implements es seguida por
el nombre completo del método. El nombre completo toma la forma Namespace.NombreClase.NombreMiembro. A menos que se haya añadido un Namespace o cambiado las propiedades del proyecto por defecto,
el Namespace es el mismo que el nombre del
proyecto.
Agregar un campo para la propiedad Y, e implementar la propiedad Y.
Private m_y As Integer = 0
Public Property Y() As Integer Implements
Interfaz.IMover.Y
Get
Return m_y
End Get
Set(ByVal value As Integer)
m_y = value
End Set
End Property
Public Sub Mover(ByVal
aDirection As Direccion, ByVal Distancia As Integer) Implements
Interfaz.IMover.Mover
Select Case aDirection
Case
Direccion.Arriba
m_y +=
Distancia
Case
(Direccion.Abajo)
m_y -= Distancia
Case
(Direccion.Izquierda)
m_x -= Distancia
Case
(Direccion.Derecha)
m_x += Distancia
End Select
End Sub
Añadir un método a la
clase CPeon que no forma parte del interfaz IMover.
Private
m_capturado As Boolean
= False
Public Property Capturado() As
Boolean
Get
Return
(m_capturado)
End Get
Set(ByVal Value As Boolean)
m_capturado = Value
End Set
End Property
Esto completa la
implementación del interfaz IMover en la clase CPeon.
Testear
el interface IMover.
Cuando se crean proyectos
de tipo console application, Visual Studio .NET crea un método
start-up. Ahora añadiremos
código a este método para testear la clase CPeon.
1. Hacer doble click sobre
IMover.vb
2. Añadir código al método
Main. Notar que movil es declarado como IMover e instanciado como CPeon, no se
puede instanciar un interface, este no tiene implementación.
Sub Main()
Dim movil As IMover = New
CPeon()
movil.X =
10
movil.Y = 10
Console.WriteLine("X:{0} Y:{1}", movil.X, movil.Y)
Console.WriteLine("Moviendo arriba 5 espacios.")
movil.Mover(Direccion.Arriba, 5)
Console.WriteLine("X:{0} Y:{1}", movil.X, movil.Y)
Dim unPeon As
CPeon = CType(movil, CPeon)
Console.WriteLine("Is the pawn captured? {0}", unPeon.Capturado)
End Sub
Utilizar una referencia a una interfaz es similar al
uso de una referencia a una clase base. La
variable de referencia movil sólo tiene
acceso a los miembros de IMover, aunque se puede establecer para
referirse a una instancia de CPeon. Para acceder
a los miembros de CPeon de la referencia de movil, se debe convertir la referencia a CPeon. Posteriormente podemos hacer que la referencia a movil apunte a otras piezas del juego, como la Torre o un
Caballo. Cuando escribimos el código, buscamos en las listas de IntelliSense para
ver estas diferencias.
3. Presionar
Ctrl + F5 para ejecutar el programa. Si presionamos F5, la salida parpadea brevemente.
Al ejecutar el programa con Ctrl + F5 nos da la oportunidad de examinar la
salida.
No hay comentarios:
Publicar un comentario