Conociendo C# Pt. 3: Interfaces y polimorfismo

Estuve un buen rato pensando cómo hacer esto en partes separadas, pero los conceptos están tan atados que es conveniente tratarlos juntos. Antes que nada, estos temas pueden parecer confusos al principio, pero voy a intentar escribirlo de la mejor manera posible, y como siempre usando ejemplos.

Interfaces

Estas entidades a veces son equiparadas con el concepto de contratos, en el sentido que definen propiedades y métodos, pero no implementación. En una interfaz vamos a encontrar poco y nada de código, y exclusivamente declarativo. Una interfaz por si sola no hace absolutamente nada, en cambio tiene que ser implementada por una clase o struct. Esto quiere decir que absolutamente todo lo que está declarado en la interfaz va a estar declarado también en la clase que la implemente.

En este caso tenemos el código del Ministerio Simulator, hay varios elementos de la escena que son interactuables, pero dentro de esos elementos hay categorías interactuable. Tenemos la mesa de formulario, la mesa de sello, la trituradora, la mesa de entrega y la fotocopiadora. Todos estos elementos se comportan diferentes, pero todos tienen algo en común, son interactuables de la misma manera, hay un área inmediatamente próxima a ellos que detecta si hay un jugador cerca y si este presiona el botón de interactuar, el objeto interactúa. Por ende, podemos decir que todos estos elementos pueden implementar una interfaz que obligue a cada uno de ellos a tener interacción y que sea consistente entre cada uno.

Interfaz
Definición de interfaz IInteractable, usualmente la nomenclatura para interfaz es un verbo con terminación able (convirtiéndolo en adjetivo) con una ‘I’ adelante. Ejemplo: IDestructible

La interfaz siempre debería describir los miembros necesarios para su uso correcto. Una clase puede implementar varias interfaces, así que no es necesario hacer interfaces súper complejas, con que cada una describa un concepto compartido como Destructible, Recogible, Caminable, etc, ya basta.

FormDesk
La clase FormDesk implementa IInteractable, es en la implementación mismo que vemos que tipo de comportamiento van a tener los miembros declarados en la interfaz.

Polimorfismo

Acá es donde entra la razón por la cual usar interfaces. Las interfaces pueden ser usadas como tipos al declarar una variable, propiedad, método, colección o lo que sea donde esperarías un tipo. Esto quiere decir que yo puedo referenciar una mesa de formulario de dos maneras, implícitamente con el tipo FormDesk, o genéricamente usando la interfaz IInteractable. A esto se le llama polimorfismo, la posibilidad de referirte a un objeto por medio de una interfaz o un padre sin referirte explícitamente a él.

variable interactable
Este campo es de tipo IInteractable, permitiendo asignarle una referencia a cualquier instancia de una clase que implemente esta interfaz.
method
Naturalmente, no estoy referenciando directamente a la clase, por ende, solo voy a tener acceso a los métodos y propiedades declarados en la interfaz.

Y en la hora de asignar esta variable, podemos asignar directamente cualquier instancia de clase que implemente la interfaz o referirnos a una instancia de clase usando la interfaz como tipo de dicha clase, no es necesario encapsular nada.

asignando
En este caso, el componente que va a extraerse del padre puede ser FormDesk, o AttachmentDesk, o cualquier clase que implemente IInteractable. Simplemente va a ser extraída como tipo IInteractable.
asignaciones
Ambas asignaciones son válidas, pero al momento de consumir la referencia interact sin transformaciones solo vamos a tener acceso a los miembros declarados en la interfaz.

En conclusión, las interfaces proveen una forma implícita de agrupar scripts de manera que estos sean accesibles por medio de las características que comparten por implementar dicha interfaz. Pero se preguntarán, ¿cómo hago para acceder al código especifico de la clase teniendo la referencia a esa clase como una interfaz? ¿es posible?

Si, aunque no es recomendado, lo ideal es hacer todo de la manera más genérica posible, habiendo dicho esto, pueden acceder al comportamiento especifico de una clase casteando desde la interfaz al tipo específico.

casting
Casteo seguro, cuando usamos la palabra as para castear de un tipo a otro, en el caso que no sea casteable, la referencia será nula.

 

Implementación en Unity

Unity no sabe interpretar los campos públicos definidos con tipo de Interfaz. Para eso podemos usar herencia.

 

Responder

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