Fundamentos de AS3: Definición de métodos


action
Los métodos son una parte fundamental de las clases. Sin ellos sólo servirían para albergar datos.

Una clase es mucho más que una base de datos. Definen lo que un objeto puede hacer, con sus datos y con los de otros objetos.

Si las propiedades son la información, los métodos son la acción.

En este artículo vamos a ver como definir los métodos de una clase. También aprenderemos como pasarles la información que necesitan, si ésta no está en las propiedades de dicha clase.

También estudiaremos qué hacer para que nos devuelvan información cuando terminan de ejecutar sus acciones, si es que ésto es necesario.

Volver al Índice

Introducción

Las funciones encapsulan comportamiento

Una función es un bloque de código con entidad propia que realiza una tarea específica. A este bloque de código le llamaremos cuerpo de la función

A veces, las funciones reciben datos que necesitan para realizar esa tarea.

También pueden devolver un valor como resultado de esa tarea realizada.

Una vez se ha escrito una función, puede ser utilizada una y otra vez. Se suele decir que a las funciones se las llama o se las invoca cuando se utilizan desde otro lugar de nuestro código.

Esos otros lugares desde los que se puede llamar, invocar o usar una función, son otras funciones o ,mejor dicho, el cuerpo de otras funciones.

En la Programación Orientada a Objetos, las funciones son métodos de una clase. De hecho todo nuestro código se escribe dentro del cuerpo de los métodos. Por tanto, si sólo se puede invocar a un método desde otro método, debe de haber algún método de entre todas nuestras clases que se ejecute automáticamente al iniciar el programa.

Así es, y ese método, como ya hemos mencionado, es el método constructor de la clase principal.

En Fundamentos de AS3: Destripando la clase documento y su constructor. El punto de entrada a un programa, decíamos:

“… debemos asegurarnos de que el constructor contenga todas las instrucciones necesarias para que se creen e inicialicen todos los objetos necesarios para que nuestra aplicación funcione.”

Lo decíamos porque el constructor de la clase documento es el único método (y por tanto el único bloque de código) que se ejecuta automáticamente al ejecutar la aplicación.

Sin embargo, eso no significa que todo el código de nuestro programa tenga que estar escrito dentro del constructor de la clase documento.

La mayoría de los programas que usamos tienen más de 1000 líneas de código (por decir un número) ¿Te imaginas bucear entre más de 1000 líneas de código, buscando la variable a la que cambiar el valor? No, esa no es la mejor manera.

Por eso se inventaron las funciones, y después de las funciones las clases, para organizar el código y ser capaz de gestionarlo de una forma más eficiente.

Para empezar, vamos a ver como encapsular comportamiento en funciones. Cuando nos sintamos cómodos con las funciones podremos empezar a agruparlas en diferentes clases. De momento, vamos a seguir trabajando sólo con una, la clase documento.

Un método es una función que pertenece a la clase. Todos los objetos de esa clase contendrán esa función.

+

Aclaración:

Esto significa que ya tenemos un montón de métodos a nuestra disposición, los de todas las clases predefinidas en ActionScript.

Llamada a métodos predefinidos

Invocando funciones

Sin ir más lejos, en el código del ejemplo que utilizábamos en el artículo que he citado antes, ya estábamos llamando a un método de una de esas clases: el método addChild() de la clase MovieClip.

Recordemos el código de este ejemplo:

		package  
		{
			import flash.display.MovieClip;
			
			public class Main extends MovieClip 
			{
				public function Main() 
				{
					var miPelota:Pelota = new Pelota();
					addChild(miPelota);
					miPelota.x = 100;
					miPelota.y = 175;
				}
			}
		}

La sentencia addChild(miPelota);, en la línea 10, añade una instancia de la clase Pelota a la pantalla. Recuerda que Pelota era una clase exportada desde la biblioteca de Flash, a partir de un símbolo.

+

Aclaración:

Entre paréntesis le estamos pasando la información que necesita, es decir, qué objeto queremos que el método añada a la pantalla.

¿Cómo sabemos que datos necesita? En el caso de addChild() es evidente, pero en otros no tiene porqué serlo.

  1. Si el método está predefinido tendremos que sabérnoslo o leer la documentación de Flash para ese método.
    Mirad por ejemplo la del método addChild(). (Si no aparece el segundo en la lista, pulsado sobre Mostrar métodos públicos heredados)
    Si hacési click en la entrada veréis una explicacion detallada de lo que hace el métdo y explicaciones de los parámetros que debe recibir, el valor que devuelve, los eventos que se disparan, ejemplos, etc.

    La información contenida en la Referencia de ActionScript 3.0 es muy valiosa y siempre deberías tener esta página a mano, guardala en los favoritos de tu navegador.

  2. Si el método lo definimos nosotros, habremos definido nosotros mismos los parámetros para que reciba esos datos, así que ya lo sabremos

Ejecutar métodos

Para invocar un método escribimos su nombre seguido de los valores para los parámetros que necesite, separados por comas y entre paréntesis. Si no tiene definidos parámetros, no ponemos ningún valor, pero ponemos los paréntesis de todos modos.

Además:

  • El número de valores (separados por comas) que se le pasan como argumentos al método debe ser el mismo que el número de parámetros definidos.
  • El orden y el tipo de dato de los valores entre paréntesis deben ser también los mismos que los declarados en la sentencia de definición del método.
  • Si una clase A extiende a otra clase B, se pueden invocar todos los métodos de la clase B desde la clase A. A hereda los métodos de B.

Usar, llamar, invocar y ejecutar son sinónimos cuando hablamos de los métodos o las funciones.

Ya que estamos hablando de llamadas a métodos, no parece justo olvidar la llamada al método constructor de Pelota (en la línea 9 del ejemplo)

		var miPelota:Pelota = new Pelota();
		

Cuando llamamos a un método constructor, tenemos que poner, delante del nombre del mismo, la palabra clave new.

Definición de un método

No nos basta con los métodos predefinidos ¡Queremos más!

Supongamos que queremos que nuestro programa ponga más pelotas rojas en la pantalla. Repetir esas cuatro líneas varias veces y cambiar las coordenadas para que cada pelota aparezca en un lugar diferente no parece un gran problema. A no ser que queramos poner muchas pelotas en juego.
Supongamos que es así, que queremos poner muchas.

Repetir el código cada vez que queramos realizar un conjunto de operaciones similares no parece muy inteligente y no lo es. Definir un método que realice esas acciones y llamarlo cada vez que lo necesitemos suena mucho mejor.

Vamos a hacer lo último:

		package  
		{
			import flash.display.MovieClip;
			
			public class Main extends MovieClip 
			{
				public function Main() 
				{
					colocarPelota();
				}
				
				private function colocarPelota():void
				{
					var miPelota:Pelota = new Pelota();
					addChild(miPelota);
					miPelota.x = 100;
					miPelota.y = 175;
				}
			}
		}
		

Esto debería funcionar y funciona. Ahora cada vez que queramos crear una pelota, sólo tenemos que llamar o invocar a colocarPelota().

Si miramos atentamente el código entre las líneas 12 y 18, podemos deducir que la definición de un método consta de dos partes:

  1. La sentencia de definición del método (línea 12). Consta a su vez de:
    • un atributo de acceso, que en este caso es private (veremos lo que significan los atributos de acceso más adelante)
    • la palabra clave function, por si dudábamos que un método es una función
    • el nombre del método, en este caso colocarPelota
    • una lista de parámetros separados por comas y entre paréntesis.
      Aunque nuestro método no reciba parámetros, como es el caso, tenemos que poner los paréntesis
    • el tipo de dato del valor de retorno, separado de todo lo anterior por dos puntos (:).
      Si no ha valor de retorno, como en nuestro caso, hay que poner void, el tipo de datos vacío
    • De estas dos últimas partes, vamos a hablar en detalle en las dos secciones siguientes, así que no te preocupes de masiado por ellas todavía.

  2. El cuerpo del método (líneas 13 a 18), que va entre llaves porque es un bloque de código, es decir, se ejecuta del tirón, una sentencia detrás de otra.

Definir un método no garantiza que se ejecute el bloque de código que contiene su cuerpo.

El cuerpo de un método sólo se ejecuta si se llama a ese método correctamente.

+

Más Información

Y queremos que sean útiles!!!

¿Lo es colocarPelota() tal y como lo hemos definido?. Simplemente hemos copiado las sentencias que había en el constructor y las hemos pegado en el nuevo método. El constructor ahora llama al método en vez de ejecutar las líneas él mismo. Se dice que está delegando en colocarPelota() para realizar esas tareas.

En este sentido podemos decir que es útil, porque el código queda mejor organizado, sobre todo si el constructor realizara más tareas. Así las que tienen que ver con colocar la pelota en pantalla están claramente organizadas y separadas del resto.

El constructor puede llamar a colocarPelota() tantas veces como se quiera. Y las pelotas serán creadas por éste método y añadidas a la pantalla, … espera un momento… pero ¡Todas en el mismo lugar!
Esto no parece demasiado útil, ni divertido, porque no lo es. Lo que realmente sería divertido y útil es que pudiéramos decirle al método colocarPelota() en qué coordenadas quiero que las coloque.

Esto sería dar un paso hacia adelante; hacia lo que en POO se denomina abstracción, que aplicado a este método consistiría en parametrizar lo que queramos que pueda variar de un caso a otro: las coordenadas de la pelota.

Lo vemos en el siguiente apartado.

Métodos con Parámetros

Métodos que reciben información de quien les invoca. Parámetros de una función.

Lo que realmente queremos es poder invocar a colocar pelota de esta manera:

		colocarPelota(200,300);
		

para que coloque la pelota en las coordenadas x = 200, e y = 300, o en otras, si cambiamos esos números en la llamada.

Redefinamos entonces colocarPelota() para que acepte las coordenadas donde tiene que colocar cada instancia de Pelota.

		//...
				private function colocarPelota(xPos:Number, yPos:Number):void
				{
					var miPelota:Pelota = new Pelota();
					addChild(miPelota);
					miPelota.x = xPos;
					miPelota.y = yPos;
				}
		//...

Fijate en la línea 12, dentro de los paréntesis tenemos dos nuevos elementos separados por una coma. A estos elementos se les llama parámetros de un método.

Definición de parámetros de un método

Los parámetros de un método son variables locales que se declaran en la sentencia de definición de un método.
Se colocan dentro de los paréntesis que van detrás del nombre del método y se separan con comas (,).
Cada parámetro debe especificar un nombre de variable y, separándolo con dos puntos (:), el tipo de valor que puede recibir.

De nuevo en la línea 12, observa como hemos llamado a las variables de los parámetros xPos e yPos, respectivamente. Y que hemos declarado que si tipo de dato es Number, por que van a recibir números.

Invocar funciones con parámetros

Ahora, cada vez que lo invoquemos, tendremos que darle valores para esos parámetros, y él utilizará esos valores en las líneas 6 y 7.

En un momento explicamos os detalles, pero no puedo resistir la oportunidad de probar qué tal funciona ésto. Observa como llamo al colocarPelota() desde el constructor:

		package  
		{
			import flash.display.MovieClip;
			
			public class Main extends MovieClip 
			{
				public function Main() 
				{
					colocarPelota(200,300);
					colocarPelota(400,100);
					colocarPelota(80,120);
					colocarPelota(275,200);
				}
				
				private function colocarPelota(xPos:Number, yPos:Number):void
				{
					var miPelota:Pelota = new Pelota();
					addChild(miPelota);
					miPelota.x = xPos;
					miPelota.y = yPos;
				}
			}
		}

Y he aquí el resultado:
Fundamentos AS3_Definicion de metodos_01
Ahora sí, esto es otra cosa. Puedo crear nuevas pelotas y colocarlas donde quiera con una sola línea.

Invocar una función con parámetros

Para invocar un método que recibe parámetros, escribimos su nombre seguido de los valores para los parámetros que necesite, separados por comas y entre paréntesis.

  • El número de valores (separados por comas) que se le pasan como argumentos al método debe ser el mismo que el número de parámetros definidos.
  • El orden y el tipo de dato de los valores entre paréntesis deben ser también los mismos que los declarados en la sentencia de definición del método.
+

Más Información

Valor de retorno de un método

Métodos que devuelven información a quien los invoca.

A veces tenemos que realizar el mismo cálculo en diferentes lugares de nuestro código, y no nos interesa teclear todo el código de la operación en cada uno de ellos.

Los métodos con valor de retorno sirven para eso.

Veamos primero un ejemplo de uso con un método ya definido en el lenguaje ActionScript.

Imagina que queremos un número aleatorio entero entre 0 y 10. AS3 tiene una clase un poco especial que se llama Math y que define métodos que calculan cosas más o menos complejas para nosotros.

Math.random() es uno de ellos: Calcula un número aleatorio entre 0 y 1 y nos lo devuelve. ¿Qué significa que nos lo devuelva? Significa que allá donde escribamos Math.random(), esta expresión será sustituida por el valor que calcula.
Por ejemplo:

		var numAleatorio:Number = Math.random();
		trace(numAleatorio);
		

Supongamos que el Math.random() de la línea 1 genera como resultado 0.75643281. Sería como si hubiéramos escrito:

		var numAleatorio:Number = 0.75643281;
		trace(numAleatorio);
		

Ésto es lo que significa que un método, en este cado Math.random() devuelva un valor.

Ahora bien, ¿Cómo hacemos para que un método definido por nosotros devuelva un valor o un objeto?
Utilizando, lo que se denomina, una sentencia return al final del cuerpo del método y especificando, en la sentencia de definición del método el tipo de valor u objeto que devuelve.
Esta imagen ilustra como sería una función que devuelve la suma de dos números:
3_1_ElementosDeUnaClase02

Vamos a ver otro ejemplo que nos va a resultar útil más de una vez. Uno de los cálculos que más a menudo se realizan en programación (sobre todo para colocar elementos en pantalla utilizando posicionamiento relativo) es calcular un tanto por ciento de una cantidad determinanda (p.ej.: el 75% del ancho de la pantalla).

La función que realizaría el cálculo por nosotros necesita saber dos cosas, el tanto por ciento que queremos calcular y la cantidad de la que queremos calcular ese porcentaje, por lo que recibirá esta información en dos parámetros de tipo Number.

Ahora, este método tiene que devolverme el resultado, que también es un número, así que el tipo del valor de retorno también es un Number.

Crea otro proyecto de flash y teclea éste código en su clase documento (que hemos llamado Main, como siempre).

		package  
		{
			import flash.display.MovieClip;
			
			public class Main extends MovieClip 
			{
				public function Main() 
				{
					trace("75% del ancho de la pantalla:" + tantoPorCiento(stage.stageWidth, 75) );
					trace("10% del alto de la pantalla:" + tantoPorCiento(stage.stageWidth, 10) );
					// También podemos almacenar el valor de retorno en una variable:
					var area25:Number = tantoPorCiento(stage.stageWidth * stage.stageHeight, 25);
					trace("25% de la superficie de la pantalla:" + area25 + " pixeles cuadrados.");
				}
				
				private function tantoPorCiento(cantidad:Number, porcentaje:Number):Number
				{
					var resultado:Number = cantidad*porcentaje/100;
					return resultado;
				}
			}
		}

Si compilas este proyecto pulsando Ctrl + Enter (o Cmd + Enter en Mac) en el panel Output aparecerá lo siguiente.
75% del ancho de la pantalla:412.5
10% del alto de la pantalla:55
25% de la superficie de la pantalla:55000 pixeles cuadrados.

Suponiendo que las dimensiones de tu proyecto de Flash son 550×400 pixeles.

Como puedes ver, el lugar dónde escribimos la llamada a la función, es el lugar al que el valor de retorno es devuelto.
Obtenemos así el mismo resultado que si hubiéramos hecho el cálculo u operación a mano y lo hubiéramos escrito ahí directamente.

+

Acerca de la función trace()

Pero el valor de retorno de un método o función no sólo puede ser un número, puede ser también una cadena de texto, un valor booleano (true o false),…

También puede ser un objeto. Sígueme a la siguiente sección para verlo.

Síntesis final

Definición de métodos

La siguiente figura resume diferentes partes de la definición de un método que calcula y devuelve la media de tres números.
AnatomiaMetodo
La definición de un método (por orden de aparición) consta de dos partes: la sentencia de definición y el cuerpo del método.

  • La sentencia de definición consta (por orden de aparición) de:
    • un modificador de acceso (private de momento, excepto para el método constructor, que usará siempre public),
    • la palabra clave function,
    • el nombre del método,
    • la declaración de los parámetros de la función entre paréntesis.
      Si no hay parámetros que declarar hay que poner los paréntesis de todos modos.
      Si hay que definir varios parámetros, se separarán con comas.
      Estamos definiendo variables, y por eso debemos poner el tipo de dato que van a recibir, separado de su nombre por :
    • Después hay que poner el tipo de valor de retorno, precedido por dos puntos : (si no hay valor de retorno hay que poner void).
  • Después va el cuerpo del método, entre llaves, con todas las instrucciones necesarias para que este realice su función:
    • Las variables declaradas dentro del cuerpo de un método son variables locales. Cuando acaba de ejecutarse el método esa variable desaparece y no puede ser utilizada desde ningún otro método. Tampoco conserva el valor entre llamada y llamada al mismo método.
    • Dentro del cuerpo del método, los parámetros funcionarán como variables locales que se hubieran definido con var. Su valor será el valor que se le pase al método en su invocación.
    • Si se ha especificado un tipo de valor de retorno, la última sentencia del cuerpo del método debe ser un return seguido del valor que se quiera retornar o de la variable que lo contenga.
      Este valor puede ser también un objeto.

Ejemplo 1:
Un método que recibe tres parámetros y no devuelve ningún valor:

		private function actualizarPosicion(objeto:MovieClip, velX:Number, velY:Number):void
		{
			objeto.x = objeto.x + vX;
			objeto.y = objeto.y + vY;
		}
		

Ejemplo 2:
Un método que devuelve el valor de la distancia entre dos instancias de MovieClip o de clases que extiendan a MovieClip

		private function distancia(objDesde:MovieClip, objHasta:MovieClip):Number
		{
			var distanciaX:Number = objHasta.x – objDesde.y;
			var distanciaY:Number = objHasta.x – objDesde.y;
			return Math.sqrt( distanciaX*distanciaX + distanciaY*distanciaY );
		}
		

Math.sqrt() (square root) devuelve la raíz cuadrada de un número.

Ejemplo 3:
Un método que no recibe parámetros, pero devuelve un valor que es un objeto de la
clase MovieClip con el dibujo de un cuadrado dentro

		public function crearCuadrado():MovieClip
		{
			var cuadrado:MovieClip = new MovieClip();
			cuadrado.graphics.lineStyle(2, 0x009000);
			cadrado.graphics.drawRectangle(0, 0, 10,10);
			return cuadrado;
		}
		

Llamada a métodos

  • Usar, llamar, invocar y ejecutar son sinónimos cuando hablamos de los métodos o las funciones.
  • Para invocar un método escribimos su nombre seguido de los valores para los parámetros que necesite, separados por comas y entre paréntesis. Si no tiene definidos parámetros, no ponemos ningún valor, pero ponemos los paréntesis de todos modos.
  • El número de valores (separados por comas) que se le pasan como argumentos al método debe ser el mismo que el número de parámetros definidos.
  • El orden y el tipo de dato de los valores entre paréntesis deben ser también los mismos que los declarados en la sentencia de definición del método.
    Usando el método definido en el ejemplo 1 de esta sección:

    			//...
    			var miPelota:MovieClip = new Pelota();
    			//...
    			actualizarPosicion(miPelota, 2, -3);
    			//...
    			

    Fijate en que miPelota es de tipo MovieClip, mientras el constructor que invocamos es el de Pelota para que este código funcione Pelota tiene que extender a MovieClip.

  • Si el método devuelve un valor, es decir, tiene un valor de retorno definido, podemos usarlo directamente asignando la llamada al método a una variable que tengamos definida o que definamos en la misma sentencia. El valor devuelto por la función quedará asignado a la variable.
    			// Suponiendo que pelota1 y pelota2 son Movieclips u objetos de una clase
    			// que extiende a MovieClip
    			var separacionPelotas:Number = distancia(pelota1, pelota2);
    			//...
  • Si una clase A extiende a otra clase B, se pueden invocar todos los métodos (y propieades) de la clase B desde la clase A. A hereda los métodos (y propiedades) de B.

Piensa que las funciones son como máquinas. Los lenguajes de programación definen herramientas muy versátiles para diseñar y crear esas máquinas.
Las variables y propiedades que se utilizan desde el cuerpo de una función, qué parámetros necesita y que información devuelve, son factores que condicionan lo transportable que es un método de un proyecto a otro.
Recuerda que los programadores somos vagos y no nos gusta reescribir código. Si diseñas bien tus métodos, podrás utilizarlos fácilmente en otros proyectos. ¡Larga vida al copy/paste!.

Para terminar, vamos a retomar nuestro punto de partida, el constructo de la clase documento y la cita:

“… debemos asegurarnos de que el constructor contenga todas las instrucciones necesarias para que se creen e inicialicen todos los objetos necesarios para que nuestra aplicación funcione.”

En un programa largo no vamos a querer que todo nuestro código esté en el constructor. Lo vamos a organizar en varios métodos, y el constructor delegará en los que sea necesario para la correcta inicialización de nuestro programa.
Así en el ejemplo inicial de la pelota, podríamos escribir:

		package 
		{
			import flash.display.MovieClip;
			 
			public class Main extends MovieClip
			{
				public function Main()
				{
					var pelota:MovieClip = new Pelota();
					colocarObjeto(pelota, 100, 100);
					
					var cuadrado:MovieClip = new Cuadrado();
					colocarObjeto(cuadrado, 350, 100);
					
					var triangulo:MovieClip = new Triangulo();
					colocarObjeto(triangulo, 225, 250);
					
					//... y así tantos objetos como necesite nuestro programa
				}
				 
				private function colocarObjeto(objeto:MovieClip, xPos:Number, yPos:Number):void
				{
					addChild(objeto);
					objeto.x = xPos;
					objeto.y = yPos;
				}
			}
		}		

Como puedes ver así queda mucho más legible que si colocamos a manubrio cada objeto dentro del constructor, aparte de que tenemos que escribir bastante menos.

Ahora que sabemos tanto de funciones y métodos podemos reescribirla de un modo mucho más preciso:

“… debemos asegurarnos de que el constructor contenga todas las instrucciones y/o llamadas a métodos que sean necesarias para que se creen e inicialicen todos los objetos necesarios para que nuestra aplicación funcione.”

Ok, creo que es suficiente. Tómate tu tiempo para asimilar toda esta información.

No dudes en jugar con los ejemplos y dejarme un comentario si no entiendes o no te sale algo.

Volver al Índice

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 )

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 )

Google+ photo

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

Conectando a %s