Escribe tu búsqueda

Xojo: Constructores, subclases y POO

Compartir

Las clases en un Lenguaje de Programación Orientado a Objetos (POO) son tan importantes que esta semana son también el núcleo de nuestro artículo sobre Xojo. Después de todo, los mecanismos que nos ofrece el lenguaje para su definición son los que nos permitirán crear clases más flexibles, versátiles, reutilizables y, por tanto, la capacidad de realizar aplicaciones con mayor rapidez gracias a la mera composición en la mayoría de los casos de nuestras piezas, además de un código más fácil de mantener gracias a la encapsulación.

En el anterior artículo vimos como crear nuestra primera clase, la relación entre clase y objetos, la definición de propiedades, métodos y la relación que hay entre los métodos específicos encargados de definir o recuperar los valores de las propiedades, conocidos normalmente como setters y getters y que en el caso de Xojo existe una forma mejor y más rápida de escribir el código correspondiente mediante el uso de las Propiedades Compartidas.

También vimos que para trabajar con un objeto (instancia de clase) hay que utilizar la palabra clave ‘New’ durante la asignación a una variable y que, posteriormente, ya era posible llamar a los métodos del objeto, en la mayoría de los casos para definir las propiedades del mismo. Ahora bien, ¿no sería estupendo si pudiésemos realizar esas dos operaciones con una única línea de código? Es decir, ser capaces de asignar por ejemplo el nombre y apellidos de nuestra clase ‘Persona’ durante la propia creación del objeto.

Constructores de Clase

Pues lo cierto es que sí, se puede. Y para ello se utilizan un tipo de métodos especiales denominados “Constructores”. En Xojo los constructores se ejecutan durante la inicialización de la instancia y admiten parámetros al igual que ocurre con cualquier otro método, si bien no es obligatorio que un Constructor deba de tener parámetros de entrada.

Para crear el Constructor de una clase se utiliza la misma opción de menú que en el caso de cualquier otro método (por ejemplo el atajo de teclado Comando + Opción + M). En este caso, no obstante, en el panel de Inspector resultante deberemos de seleccionar la opción ‘Constructor’ en el menú desplegable correspondiente a ‘Method Name’.

Como hemos dicho, un Constructor de clase puede recibir parámetros, y en el caso de nuestra clase de ejemplo ‘Persona’ dichos parámetros son los correspondientes al nombre, apellido, edad y sexo, de modo que hemos de declararlos en el área correspondiente a ‘Parameters’. Por último, dejaremos la visibilidad del método Constructor definida como ‘Public’, de modo que pueda efectivamente ser llamado durante la creación de una instancia de la clase.

A continuación, introduciremos el código de inicialización correspondiente en el área del Editor de Código. Con nuestra clase de ejemplo ‘Persona’ dicho código se limita a la asignación de los diferentes parámetros recibidos a cada una de las propiedades de la clase (nombre, apellido, edad y sexo).

Verás que hemos introducido una nueva partícula del lenguaje: ‘self‘ y que hace referencia a la clase que contiene el código en cuestión. De hecho, su uso puede considerarse como redundante, dado que si no incluyésemos dicha partícula en nuestro código se estaría utilizando por omisión, pero de este modo mejora su legibilidad.

Por último, utilizaremos por ejemplo el Evento ‘Open’ de la ventana Window1 para crear una nueva instancia de nuestra clase utilizando en este caso el constructor:

dim mPersona as new Persona("Javier", "Rodriguez", 33, true)

Así, hemos resumido a una única línea de código lo que en el ejemplo de la semana pasada nos llevaba varias: declaración de la variable con la creación de una nueva instancia de la clase ‘Persona’, y varias líneas con las correspondientes llamadas para cada uno de los métodos encargados de asignar valor a cada uno de los parámetros de la clase.

Como puedes comprobar, este es el primero de nuestros métodos en el que definimos varios parámetros de entrada. Cuando es así, separaremos cada una de las definiciones mediante el uso del caracter coma (‘,’); y posteriormente hemos de tener cuidado a la hora de invocar el método en cuestión, asegurándonos que pasamos la información en el orden esperado y con la correspondencia de tipo declarada.

De no ser así, podremos o bien recibir un mensaje de error por parte del Compilador de Xojo (el mejor de los casos), o bien contar con un programa que no se comporta tal y como esperamos porque no estamos manejando los datos de la forma esperada. Por ejemplo, ‘Nombre’ y ‘Apellido’ están declarados en ambos casos como tipo String de modo que el Compilador no mostraría ningún error si escribiéramos lo siguiente:

Dim p as new persona("Rodriguez", "Javier", 33, true)

Sin embargo, nuestro Constructor de clase estaría asignando “Rodriguez” a la propiedad “nombre” y “Javier” a la propiedad “Apellido”. Tendríamos un problema.

Sobrecarga de métodos

¿Y qué ocurrirá si pasas menos valores que los esperados por la declaración del método (en este caso el Constructor de la Clase)? Prueba lo siguiente y ejecuta a continuación el programa:

Dim p as new persona("Javier", "Rodriguez")

Recibirás un mensaje de error por parte del Compilador indicando que el método esperaba una mayor cantidad de parámetros que los recibidos. Sin embargo, puede darse el caso de que durante la creación de una instancia del clase no siempre tengas todos los valores para la correcta inicialización de todos sus parámetros, como en este ejemplo. ¿Qué podemos hacer entonces?

La respuesta está en otro de los principios de la programación orientada a objetos. Se trata de la Sobrecarga de métodos, donde podemos declarar varios métodos en una misma clase utilizando el mismo nombre (nomenclatura) pero con la única condición de que variemos la cantidad y/o correspondencia de tipo de los parámetros declarados por el método. Luego, será el compilador el encargado de saber cuál de los métodos ha de invocarse en función de esta información.

Para poner la teoría en práctica, crearemos un nuevo método Constructor (mismo nombre, de modo que se cumple la primera de las reglas de la sobrecarga de métodos), y en este caso sólo declararemos dos parámetros de tipo String (diferente número de parámetros declarados, cumpliendo así la segunda condición).

De igual modo, en el Editor de Código introduciremos la asignación de los parámetros sobre cada una de las propiedades. Si vuelves a ejecutar el programa en este punto comprobarás que el Compilador ya no muestra el mensaje de error y que se ejecuta correctamente.

Por otra parte el IDE de Xojo se encarga de mostrar visualmente la existencia de sobrecarga para un método determinado agrupándolos sobre una misma entrada en el Navegador de Proyecto, donde también puedes ver la signatura correspondiente a cada uno de los métodos en cuestión.

Constructores Privados y Protegidos, complicando las cosas

Si te apetece un poco de teoría adicional, perfecto; si no, puedes pasar tranquilamente al siguiente apartado.

El caso es que durante la definición de un Constructor puedes marcar su visibilidad como Privada o Protegida, además de la Pública que suele ser la estándar y la que querremos utilizar en la mayoría de los casos. ¿Qué implicaciones tienen las otras dos opciones?

La visibilidad Privada en un Constructor se utiliza en las clases Virtuales. Estas son clases que no se pueden instanciar (es decir, no podrás crear objetos a partir de ellas), sino que sirven como meras plantillas o clases base a partir de las cuales se crean (derivan) otras clases. Para ello, el constructor marcado como Privado no deberá de aceptar ningún parámetro.

Por otra parte, cuando marcamos el Constructor de una clase como ‘Protegido’ estaremos obligando a que cualquier clase derivada deba de realizar su propia implementación de dicho constructor (Overriding), concepto que veremos en el siguiente apartado.

Subclases, cuestión de herencia

Otro de los principios básicos de la programación orientada a objetos es la capacidad de crear nuevas clases a partir de otras ya existentes. Así conseguimos nuevas formas de especialización para un tipo de dato determinado sin necesidad de tener que escribir todo el código relacionado desde cero. De hecho, en Xojo encontrarás muchas clases que siguen este principio como pueda ser por ejemplo AutoDiscovery.

Una de las cualidades inherentes a la creación de una nueva clase a partir de otra ya existente (subclase) es la Herencia. Así, tal y como ocurre en la propia naturaleza, la nueva clase heredará y podrá acceder a todos los métodos y propiedades cuya visibilidad no sea Privada. Veámoslo con un ejemplo.

En nuestro proyecto crearemos una nueva clase Artista como subclase de Persona (un artista es una especialización de la clase tipo Persona).

En el panel Inspector utilizaremos por primera vez el campo ‘Super’ introduciendo en él el nombre correspondiente a la clase que queremos utilizar como punto de partida o clase ‘Superior’ a la definida; introduce el texto ‘Persona’ en dicho campo. A continuación crea una nueva Propiedad ‘actividad’ de tipo ‘String’ y conviértela a Propiedad Computada.

Ahora utiliza la combinación de teclas Comando + Opción + M para crear un nuevo método Constructor. Despliega el menú correspondiente a ‘Method Name’ y comprobarás que en esta ocasión tienes a tu disponibilidad los dos métodos constructores de la clase superior (herencia en acción).

Esta es otra de las capacidades inherentes de la programación orientada a objetos: el ‘Overriding’ o sobreescritura de métodos. Es decir, una subclase tiene la potestad de utilizar los métodos de la clase superior tal cual o bien optar por realizar su propia implementación para el mismo método. En este caso deberás de definir un método con el mismo nombre, cantidad y tipo de parámetros que el método de la clase superior al que desea sustituir.

Ahora no haremos overriding de ninguno de los métodos constructores de la clase superior, sino que nos limitaremos a crear un constructor propio de la subclase seleccionando la primera de las opciones: Constructor, declarando ‘elNombre as String, elApellido as string, laActividad as String’ como parámetros.

Una vez que confirmes la creación del método ‘Constructor’ verás que Xojo añade una serie de texto en el Editor de código. La explicación es que, por lo general, para que el objeto de una subclase pueda crearse correctamente es preciso que previamente también se proceda con la inicialización de la clase utilizada como punto de partida. Y esto será así, siempre que la clase utilizada como ‘Super’ cuente con Constructores; logicamente, si cuenta con métodos constructores es porque requiere de la inicialización de sus propiedades.

Xojo se limitará a introducir el genérico ‘super.Constructor’, pero es responsabilidad del desarrollador decidir cuál de los posibles constructores debe de llamarse, pasando en ese caso también los parámetros requeridos (como verás, Xojo también se encarga de incluir los diferentes métodos Constructores disponibles dentro de los comentarios, de modo que te resulte más sencillo utilizar cualquiera de ellos).

Borra la línea ‘Super.Constructor’ y quita los dos primeros caracteres de marca de comentario (‘//’) en la línea ‘//Constructor(elnombre as string, elapellido as String) — From Persona’, pasando así de comentario a código ejecutable. Añade la partícula ‘Super.’ al principio de la línea para indicar que deseamos ejecutar el constructor de la clase superior de la cual se deriva la actual, y elimina la definición de tipos (‘String’) y ‘–from persona’ al final de la línea para evitar el error de sintaxis. Por último incluimos la línea encargada de asignar el parámetro ‘laActividad’ sobre la propiedad ‘actividad’ de la subclase que estamos creando.

Regresa ahora al evento Open de Window1 y sustituye el código por el siguiente:

dim mPersona as new Artista("Salvador", "Dalí","Pintor")

Ejecuta la aplicación. ¡Voilà! hemos creado un objeto ‘Artista’ que se corresponde con una subclase derivada de ‘Persona’ y que somos capaces de Construir pasando los parámetros requeridos por uno de los constructores de la clase superior al tiempo que también inicializamos correctamente los parámetros correspondientes a la propia subclase: ‘Actividad’.

Veamos ahora otra cualidad de la herencia en acción. Añade el siguiente código al evento Open de la ventana Window1:

  dim mPersona as new Artista("Salvador", "Dalí","Pintor")
  dim otraPersona as Persona
  otraPersona = mPersona
  MsgBox otraPersona.nombre + " " + otraPersona.apellido

Ejecuta el programa. Si has hecho todo correctamente verás el mensaje mostrado por la imagen. ¿Qué está ocurriendo aquí? Dado que la clase ‘Artista’ está derivada de ‘Persona’, decimos que ‘Artista también ES una ‘Persona’.

Por tanto, y con lo que ya sabemos de la correspondencia de tipos en la declaración y asignación de variables, podemos asignar un objeto ‘Artista’ sobre una variable declarada como ‘Persona’. Y gracias a lo que ya sabemos hasta el momento de la herencia de clases, el objeto ‘Artista’ contiene todos los métodos y propiedades declarados en su clase superior.

Por tanto, la variable ‘otraPersona’, declarada como tipo ‘Persona’, que contiene el objeto referenciado por ‘mPersona’ y que es de tipo ‘Artista’, puede acceder a las propiedades ‘Nombre’ y ‘Apellido’ declaradas en la clase ‘Persona’ a través de sus métodos getters. Claro, ¿no? (si la respuesta es ‘no’, revisa el anterior capítulo).

Añade la siguiente línea a continuación:

MsgBox otraPersona.actividad

Ejecuta la aplicación y verás el mensaje de error mostrado en la imagen. ¿Qué ha ocurrido aquí? Sencillo, la subclase ‘Artista’ es una ‘Persona’, dado que deriva de ésta, pero la clase ‘Persona’ NO es un ‘Artista’ y, por tanto, desconoce cuáles son las propiedades y métodos específicos definidos en dicha clase.

Después de todo recuerda que la variable ‘otraPersona’ está declarada con el tipo ‘Persona’. Es decir, la herencia de clases funciona desde arriba hacia abajo en la jerarquía, pero nunca de abajo hacia arriba (sin duda un artista es una persona, aunque no todas las personas son artistas, ¿verdad?). Hay dos formas en las que puedes solucionar el error, ¿sabrías cómo? La respuesta unas líneas más adelante.

Si bien no es el caso, en los programas complejos necesitamos saber en tiempo de ejecución si un objeto es de un tipo u otro, de modo que podamos obrar en consecuencia. Para ello, Xojo nos proporciona el operador ‘IsA’ y cuya traducción directa podría ser ‘EsUn’. Por ejemplo, la comprobación sería así:

  dim mPersona as new Artista("Salvador", "Dalí","Pintor")
  dim otraPersona as Persona
  otraPersona = mPersona
  if otraPersona IsA Artista then
    MsgBox "Es un Artista"
  else
    MsgBox "Es una persona, que no es poco"
  end if

  
Ejecuta la aplicación. Verás que aparece el diálogo con el mensaje “Es un artista”.

Sobre las dos soluciones al error anterior, la primera consiste en cambiar la declaración de la variable ‘otraPersona’ para que su tipo sea también ‘Artista’. La segunda consiste en cambiar la variable en línea que arroja el error por la correspondiente a ‘mPersona’.

Por el momento lo dejaremos aquí, y en la próxima entrega seguiremos indagando sobre otros aspectos de las clases, los bloques de nuestros programas. Hasta entonces, practica creando tus propias clases, jerarquía de clases, constructores, métodos y también pon en práctica el overriding de métodos y la sobrecarga.

Enlaces de Interés sobre Xojo

Artículos anteriores

Javier Rodríguez (@bloguintosh) es desarrollador OS X e iOS, director de Macsoluciones.com. Puedes contactar con él para el desarrollo de aplicaciones para Mac e iOS en entornos empresariales así como consultoría y formación.

Dejar un comentario

Twitter
Visit Us
Tweet
YouTube
Pinterest
LinkedIn
Share