Funciones y la estructura del programa

Funciones y la estructura del programa.

Habíamos comentado en la pequeña introducción a la Programación Orientada a Objetos que cada clase podría tener una serie de "atributos" (o "variables miembro"), que son sus características, y varios "métodos" (o "funciones miembro"), que son aquellas cosas que es capaz de hacer.

Pero hasta ahora no lo habíamos aplicado: las clases que hemos creado tenían un único método (el llamado "main", que representaba el cuerpo de la aplicación) y no tenían atributos. Ahora vamos a crear un ejemplo de clase que tendrá un par de atributos y varios métodos, unos de los cuales devolverán valores y otros no:
 

         // RectanguloTexto.java
         // Primer ejemplo de clase con varios
         //   métodos y atributos
         // Introducción a Java

         class RectanguloTexto {
 

             // --- Atributos:
             // --- la base y la altura del rectángulo

             int altura;
             int base;
 

             // --- Método "fijaAltura":
             // --- Da valor al atributo "altura"
             // --- No devuelve ningún valor

             public void fijaAltura( int valor ) {
                altura = valor;
             }
 

             // --- Método "fijaBase":
             // --- Da valor al atributo "base"
             // --- No devuelve ningún valor

             public void fijaBase( int valor ) {
                base = valor;
             }
 

             // --- Método "leeAltura":
             // --- Devuelve el valor del atributo "altura",
             // --- para no acceder directamente a él

             public int leeAltura( ) {
                return altura;
             }
 

             // --- Método "leeBase":
             // --- Devuelve el valor del atributo "base",
             // --- para no acceder directamente a él

             public int leeBase( ) {
                return base;
             }
 

             // --- Método "leeArea":
             // --- Devuelve el area del cuadrado
             // --- para no acceder directamente a él

             public int leeArea( ) {
                return altura * base;
             }
 

             // --- Método "dibuja":
             // --- Dibuja un rectangulo en pantalla
             // --- No devuelve ningún valor

             public void dibuja(  ) {

                int i, j;             // Para bucles
                String lineaActual;   // Cada linea horizontal
                                      // rectangulo que dibujamos

                for (i=0; i<altura; i++) {  // Cada fila horiz
                  // Primero la fila esta vacia
                  lineaActual = "";
                  // Luego añado cuadraditos
                  for (j=0; j<base; j++)
                    lineaActual = lineaActual + "#";
                  // Y finalmente escribo la líea
                  System.out.println( lineaActual );
                }
             }
 

             // --- Método "main":
             // --- Cuerpo de la aplicación,
             // --- Dibuja un par de rectangulos de ejemplo

             public static void main( String args[] ) {

                RectanguloTexto r = new RectanguloTexto();

                r.fijaAltura( 10 );
                r.fijaBase( 20 );
                System.out.println( "El área del rectángulo es" );
                System.out.println( r.leeArea() );
                System.out.println( "Vamos a dibujarlo..." );
                r.dibuja();
             }
 

         }
 

Comentemos cosas:


La salida de este programa sería esta:

El área del rectángulo es
200
Vamos a dibujarlo...
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################

Por lo demás, este programa no debería presentar mayor dificultad. Vemos que los métodos se definen de la forma que ya habíamos empleado para "main", salvo que en un caso general, puede ocurrir que "devuelvan" un valor de un cierto tipo, distinto de "void" (en nuestro caso, tenemos varios que devuelven números enteros -int-).

Para indicar qué valor queremos devolver, se emplea la sentencia "return", como se ve en el ejemplo.

Dentro de un cierto método podemos tener variables temporales. Es algo que ya hemos usado más de una vez en "main", con variables como las típicas "i" y "j" que empleábamos para contar en los bucles.  Estas variables auxiliares sólo existen dentro del método en el que las hemos definido. Por ejemplo, podríamos haber creado una variable auxiliar para calcular el área:
 

             public int leeArea( ) {
                int valorArea;

                valorArea =  altura * base;
                return valorArea;
             }

En este caso, hemos definido una variable llamada "valorArea". Le damos el valor que nos interesa y devolvemos ese valor. Pero no tiene sentido mencionar la variable "valorArea" desde ninguna otra parte de nuestro programa, porque desde ningún otro sitio se conoce esta variable, y obtendríamos un mensaje de error.

Esto es lo que se conoce como una "variable local" (o una "variable de ámbito local").
 

También podemos indicar parámetros (datos adicionales) para nuestros métodos. Es algo que también llevamos haciendo desde el principio, casi sin darnos cuenta. Por ejemplo, siempre hemos indicado "main" con un extraño parámetro llamado "args[]", de tipo String, y que todavía no hemos utilizado. De igual modo, cada vez que utilizamos "println", indicamos entre comillas el texto que queremos que aparezca en pantalla (y que también es un parámetro).

En este ejemplo vamos teniendo parámetros más fáciles de comprender, como en el caso de:

             public void fijaAltura( int valor ) {
                altura = valor;
             }

Este método "fijaAltura" tiene un parámetro llamado "valor", que es un número entero (int), y que es el valor que queremos que tome la altura.

Podemos indicar más de un parámetro a un método. En ese caso, los separaremos empleando comas. Por ejemplo, nos podría interesar dar valores a la vez a la base y a la altura, creando un método como éste:

             public void fijaAlturaYBase( int valorAlt, int valor Anc ) {
                altura = valorAlt;
                base = valorAnc;
             }
Todo esto es la base sobre cómo se usan las "funciones" en Java (que en este lenguaje llamamos "funciones miembro" o "métodos", siguiendo la nomenclatura habitual.en Programación Orientada a Objetos). Cada vez las iremos empleando con más frecuencia, y eso será lo que ayude a terminar de comprender su empleo en la práctica... espero...
 
Programación modular y Java.

Lo habitual en una aplicación medianamente seria es que no tengamos una sola "clase", como hasta ahora, sino que realmente existan varios objetos de distintas clases, que se relacionan entre sí.

En Java podemos definir varias clases dentro de un mismo fichero, con la única condición de que sólo una de esas clases sea declarada como "pública". En un caso general, lo más correcto será definir cada clase en un fichero. Aun así, vamos a ver primero un ejemplo que contenga dos clases en un solo fichero

         // DosClases.java
         // Primer ejemplo de una clase nuestra
         //   que accede a otra también nuestra,
         //   ambas definidas en el mismo fichero
         // Introducción a Java

         class Principal {
 

             public static void main( String args[] ) {

                Secundaria s = new Secundaria();

                s.saluda();    // Saludo de "Secundaria"
                saluda();      // Saludo de "Principal"
             }
 

             public static void saluda() {
                System.out.println( "Saludando desde <Principal>" );
             }
 

         }
 

         // ----------------------------------------------------
 

         class Secundaria {

             public void saluda() {
                System.out.println( "Saludando desde <Secundaria>" );
             }
 

         }
 

Como siempre, hay cosas que comentar:

Para compilar este programa teclearíamos, como siempre:

javac DosClases.java

y entonces se crearían dos ficheros llamados

Principal.class
Secundaria.class

que podríamos probar tecleando

java Principal

El resultado se mostraría en pantalla es:

Saludando desde <Principal>
Saludando desde <Secundaria>
 


Ahora vamos a ver un ejemplo en el que las dos clases están en dos ficheros distintos. Tendremos una clase "sumador" que sea capaz de sumar dos números (no es gran cosa, sabemos hacerlo sin necesidad de crear "clases a propósito, pero nos servirá como ejemplo) y un programa principal que la utilice.

La clase "Sumador", con un único método "calcularSuma", que acepte dos números enteros y devuelva otro número entero, sería:

         // Sumador.java
         // Segundo ejemplo de una clase nuestra
         //   que accede a otra también nuestra.
         //   Esta es la clase auxiliar, llamada
         //   desde "UsaSumador.java"
         // Introducción a Java

         class Sumador {

             public int calcularSuma( int a, int b ) {
                return a+b;
             }
 

         }

Por otra parte, la clase "UsaSumador" emplearía un objeto de la clase "Sumador", llamado "suma", desde su método "main", así:

         // UsaSumador.java
         // Segundo ejemplo de una clase nuestra
         //   que accede a otra también nuestra.
         //   Esta es la clase principal, que
         //   accede a "Sumador.java"
         // Introducción a Java

         class UsaSumador {
 

             public static void main( String args[] ) {

                Sumador suma = new Sumador();

                System.out.println( "La suma de 30 y 55 es" );
                System.out.println( suma.calcularSuma (30,55) );
             }
 

         }
 
Para compilar estos dos fuentes, si tecleamos directamente

javac usaSumador.java

recibiríamos como respuesta un mensaje de error que nos diría que no existe la clase Sumador:

UsaSumador.java:13: Class Sumador not found.
                Sumador suma = new Sumador();
                ^
UsaSumador.java:13: Class Sumador not found.
                Sumador suma = new Sumador();
                                   ^
2 errors

La forma correcta sería compilar primero "Sumador" y después "UsaSumador", para después ya poder probar el resultado:

javac Sumador.java
javac UsaSumador.java
java UsaSumador

La respuesta, como es de esperar, sería:

La suma de 30 y 55 es
85

 

 

Ejemplo.

 

Hacer la implementación de la función seno utilizando serie de Taylor.

 

La función seno puede ser calculada utilizando la serie

 

seno(x) = x – x3/3! + x5/5! – x7/7! + x9/9! - ....

 

Para llevar a cabo la implementación necesitamos de dos funciones mas, la función factorial y la función potencia.

 

Comenzaremos por escribir la función factorial. El factorial de un número se define como

 

1! = 1

2! = 1*2

3! = 1*2*3

4! = 1*2*3*4

 

n! = 1*2*3*4*5*…*n-1*n

 

y la implementación en Java queda como

 

  double factorial(int x)

  {

    int i;

    double fact = 1;

 

    for(i=1; i<=x; i++)

      fact *= i;

 

    return fact;

  }

 

Tenemos que elevar un número real a una potencia entera, así pues, si x es el número real para elevarlo a cualquier potencia hacemos :

 

x2 = x*x

x3 = x*x*x

 

xn = x*x*x* … *x

 

La implementación en Java de esta función es:

 

  double pow(double x, int n)

  {

    int i;

    double pow =1;

 

    if(x==0) return 0;

 

    for(i=1; i<=n; i++)

      pow = pow*x;

 

    return pow;

  }

 

Finalmente para llevar a cabo la función seno, definimos una clase a la cual llamamos funciones. En esta clase se encuentra definida la función seno, pow y factorial, como miembros estáticos.

 

class funciones

{

 

  public static double seno(double x)

  {

    int i;

    double s = 0;

    int signo = 1;

 

    for(i=1; i<10; i+=2)

    {

      s += signo*pow(x, i) / factorial(i);

      signo *= -1;

    }

 

    return s;

 

  }

 

  public static double factorial(int x)

  {

    int i;

    double fact = 1;

 

    for(i=1; i<=x; i++)

      fact *= i;

 

    return fact;

  }

 

  public static double pow(double x, int n)

  {

    int i;

    double pow =1;

 

    if(x==0) return 0;

 

    for(i=1; i<=n; i++)

      pow = pow*x;

 

    return pow;

  }

   

}

 

Para hacer uso de esta clase escribimos el siguiente programa.

 

class prueba

{

  static public void main(String args[])

  {

 

    int i,N;

 

    double inicio = -3.1416, fin = 3.1416, incremento = 0.1;

    

    N = (int)((fin - inicio)/incremento) + 1;

   

    double x[] = new double [N];

    double y[] = new double [N];

 

    for(i=0;  i<N; i++)

    {

      x[i] = inicio + incremento *i;

      y[i] = funciones.seno(x[i]);

    }

 

    grafica g = new grafica("Funcion seno");

    g.SerieX(x);

    g.SerieY(y);

    g.show();

  }

 

}

 

Note, en la clase prueba se están utilizando dos clases, la clase funciones y la clase gráfica. En la primera no se hace declaración de la clase, simplemente se utiliza ya que sus funciones fueron declarados como miembros estáticos. En la segunda no se da esta situación y se hace necesario hacer la declaración para su uso.

 

Regresar.