interfaces


Cuando se trata de generalizar nuestro código, existe otra forma posible de hacer esto, que tiene algunas diferencias en cuanto a su implementación, pero además ciertos usos que nos permiten definir mecánicas, inclusive con actores esto es programadores, externos que usen otros desarrollos.

Es el caso de las interfaces. Por definirlo brevemente, un interfaz es ni más ni menos, un contrato que debemos cumplir nuestro código.

La diferencia fundamental entre un interfaz y una clase base, es que la interfaz en sí misma no contiene código de ejecución. Sencillamente lo que hace este definir cómo se verán los objetos desde fuera.

A diferencia de lo que sucede con una clase base, un objeto definido por nosotros, puede implementar varias interfaces distintas, mientras que sólo puede heredar de una clase base.

Esto ha llevado a muchas discusiones teóricas, dado que en varios entornos se pretenden heredades de múltiples clase base. Aun cuando esto podría ser útil en ciertos y determinados casos, desde mi punto de vista, esto hace que el mantenimiento de ese código resulte mucho más dificultoso.

Llegado el caso de pretenderse heredar de múltiples clases, lo que debiera hacerse es definir en cascada las herencias, de modo tal de poder implementar código del más básico hasta el más especializado, y no hacer que se hereden desde clases base distintas.

Así, en el ejemplo que estábamos utilizando, la clase Vegetal que hereda de la clase SerVivo, podría a su vez ser heredada, por una clase Árbol.

Esta podría definir nueva propiedades, como tipo de raíces, formato de la hoja, cantidad ramificaciones, etc. Y luego tendríamos otras clases que al heredar de Árbol, también estarían heredando en forma indirecta de Vegetal y también de SerVivo.

Uso de Interfaces

Una cosa distinta son las interfaces. Un interfaz es, en definitiva, una especificación de algo que se debe cumplir, esto es, que cada clase  que implementa dicha interfaz, obligatoriamente debe exponer todos y cada uno de los miembros que la interfaz define.

Es en ese sentido que decimos que la interfaz es un contrato. Al existir, una biblioteca de código que conozca la interfaz, podrá acceder a cualquiera de sus métodos, aún sin tener una referencia directa, de la biblioteca de clases que implementa dichos métodos.

Esto se suele utilizar, cuando no podemos tener conocimiento claro o relación directa, con el conjunto de código con el cual vamos a tratar.

Imaginemos que por ejemplo, estamos creando un proceso, que necesita utilizar datos obtenidos de distintos orígenes, y que no sabemos a ciencia cierta, ni cuáles serán, ni cómo serán implementados.

O mejor aún, que estamos creando un componente, que sea capaz de realizar ciertas tareas, y que luego otra programadores pueden utilizar, en futuras aplicaciones o implementaciones de los orígenes de datos.

Inclusive a futuro, otro programadores de otras empresas, podrían implementar sus propios orígenes de datos sin tener que referenciar todo nuestro código, bastando sencillamente que conocieran las interfaces correctas.

Así, las interfaces podrían definirse en una biblioteca, que podría entregarse a cualquier programador externo, para que haga sus propias implementaciones de orígenes de datos, que luego nuestro componente o aplicativo pudiese utilizar sin mayores inconvenientes.

Criterios de definición de un interfaz.

Estos son los criterios básicos para la definición de cualquier interfaz.

  • No contiene código ejecutable.
  • No se pueden definir alcances: todos los miembros declarados en un interfaz son en forma predeterminada, públicos.
  • Se pueden definir tanto propiedades como métodos; si la propiedad es de sólo lectura o sólo escritura quedará consignado en la declaración del interfaz, y luego las clase que implemente solo podrán exponer estos métodos.
  • En la declaración se podrán utilizar tipo de datos personalizados, como podrían ser enumeraciones, clases personalizadas, estructuras, etc. Sin embargo, en dicho caso será conveniente, que estos tipos de datos se encuentran declarados en la misma biblioteca de clases que las interfaces, para mantenerlas aisladas del resto de los componentes, y así poder distribuirlos sin mayores inconvenientes.

Ejemplo.

El siguiente ejemplo muestra cómo sería la interfaz IVida, que se correspondería con nuestra clase base de SerVivo, si quisiéramos definir sus miembros aisladamente de la clase base.

Por convención, se suele definir el nombre de una interfaz, comenzando con I mayúscula.

VB

Public Interface IVida
    Sub Nacer()
    Sub Crecer()
    Sub Reproducir()
    Sub Morir()
    Sub GenerarEnergía()
End Interface

CS

 

interface IVida
{
    void Nacer();
    void Crecer();
        
    void Reproducir();
    void Morir();
        
    void GenerarEnergía();
}

Implementando la interfaz

 

Una vez definida un interfaz, cualquier clase que quiera indicar que cumple este contrato, deberá implementar la interfaz.

Como suele suceder, diferentes lenguajes de programación, utilizan distintos mecanismos para indicar esto. Para Visual Basic existe una palabra reservada, implements, mientras que el C#, se define exactamente igual que una herencia esto es, indicando después del nombre de declaración de la clase, el caracter dos puntos (:) y el nombre de la interfaz o interfaces que se implementan,  separados por comas. En el caso que además de implementar interfaces, se quisiera heredar de otra clase, el César la clase de la cual se hereda debe estar inmediatamente luego del carácter dos puntos.

Así quedaría entonces, la clase vegetal heredando de SerVivo e implementando IVida.

VB

Public Class Vegetal
    Inherits SerVivo
    Implements IVida
    Private Sub Fotosíntesis() Implements IVida.GenerarEnergía
    End Sub
End Class

CS

public class Vegetal : SerVivo,IVida
{
   
    private void Fotosíntesis() 
    {
    }
    void IVida.GenerarEnergía()
    {
        Fotosíntesis();
    }

Deberíamos resaltar que, mientras en Visual Basic la implementación de cada miembro de la interfaz es declarativa, utilizando la palabra reservada “Implements”, en C# la implementación se hace por coincidencia de nombre. Es por eso que, en VB, el método FotoSíntesis puede implementar directamente el GenerarEnergía de la interfaz, mientras que en C# se necesitan ambos métodos, y hacer la llamada en cascada.

Finalmente, un método que Implementa una interfaz en Visual Basic, puede ser privado (y por tanto, solo visible desde la interfaz), mientras que, nativamente, en C# debe cumplir con el alcance.

Sin embargo, como se ve en el ejemplo, el método que implementará interfaz, puedas hacerlo implícitamente, utilizando sólo el nombre del método, o como en este caso, explícitamente antecediendo al nombre del método, el nombre de la interfaz seguido por un punto.

Al hacer la llamada en cascada, el método que realmente posee el código, en nuestro ejemplo FotoSíntesis, queda declarado  igualmente como privado, con lo cual estamos obteniendo el mismo resultado final.

Son sencillamente, diferentes formas de hacer la misma cosa.

En la siguiente publicación, comenzaremos a utilizar combinatoria as de estas características, en un conjunto de bibliotecas que nos permitan realizar finalmente, tareas útiles.

Anuncios

Comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s