tecnologias

31
Tecnologías de programación Unidad 1 Programación con patrones de diseño 1.1 Conceptos Básicos de patrones. 1.1.1 Definición de patrón. Conjunto de elementos que forman una unidad diferenciada y que se repiten a lo largo del tiempo, por lo que pueden tomarse como modelo o punto de referencia. También se denomina patrón, a aquellos temas o problemáticas que se reiteran en el tiempo. 1.1.2 Clasificación de patrones. Patrones creacionales: utilizados para instanciar objetos, y así separar la implementación del cliente de la de los objetos que se utilizan. Con ellos intentamos separar la lógica de creación de objetos y encapsularla. Patrones de comportamiento: Se utilizan a la hora de definir como las clases y objetos interaccionan entre ellos. Patrones estructurales: Utilizados para crear clases u objetos incluidos dentro de estructuras más complejas 1.2 Patrones de diseño. 1.2.1 Definición de patrones de diseño. Conjuntos de soluciones a problemas comunes en el desarrollo del software. Los patrones de diseño son soluciones para problemas típicos y recurrentes que nos podemos encontrar a la hora de desarrollar una aplicación. 1.2.2 Sintaxis para la implementación de un patrón de diseño. Un patrón de diseño debe de resolver un problema de software y a su vez debe ser reutilizable es decir permitir usar el código una y otra vez o tantas veces se requiera y sea necesario. 1.2.3 Aplicaciones. Los patrones de diseños se usan durante el desarrollo de software en la solución de problemas ahorrando líneas de códigos y acelerando la construcción del sistema así mismo ayuda a prevenir futuras implementaciones cambios o errores. Unidad 2 Concurrencia de hilos 2.1 Conceptos básicos 2.1.1 Definición de concurrencia.

Upload: lennyta-hernandez

Post on 29-Jan-2016

213 views

Category:

Documents


0 download

DESCRIPTION

trabajo

TRANSCRIPT

Page 1: Tecnologias

Tecnologías de programación

Unidad 1 Programación con patrones de diseño

1.1 Conceptos Básicos de patrones.1.1.1 Definición de patrón.

Conjunto de elementos que forman una unidad diferenciada y que se repiten a lo largo del tiempo, por lo que pueden tomarse como modelo o punto de referencia. También se denomina patrón, a aquellos temas o problemáticas que se reiteran en el tiempo.

1.1.2 Clasificación de patrones.Patrones creacionales: utilizados para instanciar objetos, y así separar la implementación del cliente de la de los objetos que se utilizan. Con ellos intentamos separar la lógica de creación de objetos y encapsularla.Patrones de comportamiento: Se utilizan a la hora de definir como las clases y objetos interaccionan entre ellos.Patrones estructurales: Utilizados para crear clases u objetos incluidos dentro de estructuras más complejas

1.2 Patrones de diseño.1.2.1 Definición de patrones de diseño.

Conjuntos de soluciones a problemas comunes en el desarrollo del software. Los patrones de diseño son soluciones para problemas típicos y recurrentes que nos podemos encontrar a la hora de desarrollar una aplicación.

1.2.2 Sintaxis para la implementación de un patrón de diseño.Un patrón de diseño debe de resolver un problema de software y a su vez debe ser reutilizable es decir permitir usar el código una y otra vez o tantas veces se requiera y sea necesario.

1.2.3 Aplicaciones.Los patrones de diseños se usan durante el desarrollo de software en la solución de problemas ahorrando líneas de códigos y acelerando la construcción del sistema así mismo ayuda a prevenir futuras implementaciones cambios o errores.

Unidad 2 Concurrencia de hilos

2.1 Conceptos básicos

2.1.1 Definición de concurrencia.

La concurrencia es la propiedad de los sistemas que permiten que múltiples procesos sean ejecutados al mismo tiempo, y que potencialmente puedan interactuar entre sí, los procesos concurrentes pueden ser ejecutados realmente de forma simultánea, sólo cuando cada uno es ejecutado en diferentes procesadores. En cambio, la concurrencia es simulada si sólo existe un procesador encargado de ejecutar los procesos concurrentes, simulando la concurrencia, ocupándose de forma alternada en uno y otro proceso a pequeñísimos intervalos de tiempo. De esta manera simula que se están ejecutando a la vez.

2.1.2 Definición de hilos.

Page 2: Tecnologias

En sistemas operativos, un hilo de ejecución, hebra o subproceso es la unidad de procesamiento más pequeña que puede ser planificada por un sistema operativo.

La creación de un nuevo hilo es una característica que permite a una aplicación realizar varias tareas a la vez (concurrentemente). Los distintos hilos de ejecución comparten una serie de recursos tales como el espacio de memoria, los archivos abiertos, situación de autenticación, etc. Esta técnica permite simplificar el diseño de una aplicación que debe llevar a cabo distintas funciones simultáneamente.

Un hilo es simplemente una tarea que puede ser ejecutada al mismo tiempo con otra tarea.

Los hilos de ejecución que comparten los mismos recursos, sumados a estos recursos, son en conjunto conocidos como un proceso. El hecho de que los hilos de ejecución de un mismo proceso compartan los recursos hace que cualquiera de estos hilos pueda modificar éstos. Cuando un hilo modifica un dato en la memoria, los otros hilos acceden a ese dato modificado inmediatamente.

2.2 Implementación de hilos.

2.2.1 Estados de un hilo.

Un hilo tiene un ciclo de vida que va desde su creación hasta su terminación. Durante su ciclo de vida cada uno de los hilos o tareas de una aplicación puede estar en diferentes estados, algunos de los cuales se indican a continuación:

• Nacido: Cuando se acaba de crear un hilo, se dice que está nacido, y continúa en ese estado hasta que se invoca el método start() del hilo. La siguiente sentencia crea un nuevo thread pero no lo arranca, por lo tanto deja el thread en el estado de nacido.Thread miHilo = new MiClaseThread();Cuando un thread está en este estado, es sólo un objeto Thread vacío o nulo. No se han asignado recursos del sistema todavía para el thread. Así, cuando un thread está en este estado, lo único que se puede hacer es arrancarlo con start().

• Listo: Cuando se invoca el método start() del hilo, se dice que está en estado listo. El método se arranca con la siguiente instrucción, para el caso del hilo miHilo: miHilo.start();

• Ejecutable: cuando el método start() se ejecuta, crea los recursos del sistema necesarios para ejecutar el thread, programa el thread para Programación de Hilos: Ciclo de vida de un hilo 12 – 5 ejecutarse, y llama al método run() del thread que se ejecuta en forma secuencial. En este punto el thread está en el estado ejecutable. Se denomina así puesto que todavía no ha empezado a ejecutarse.

• En ejecución: Un hilo en estado de listo de la más alta prioridad, pasa al estado de ejecución, cuando se le asignan los recursos de un procesador, o sea cuando inicia su ejecución. Aquí el thread está en ejecución.Cada hilo tiene su prioridad, hilos con alta prioridad se ejecutan preferencialmente sobre los hilos de baja prioridad.

Page 3: Tecnologias

• No ejecutable: Un hilo continúa la ejecución de su método run(), hasta que pasa al estado de no ejecutable originado cuando ocurre alguno de los siguientes cuatro eventos:Se invoca a su método sleep().Se invoca a su método suspend().El thread utiliza su método wait() para esperar una condición variable.El thread está bloqueado durante una solicitud de entrada/salida. Por ejemplo, en el siguiente fragmento de codigo se pone a dormirmiHilo durante 10 segundos (10.000 milisegundos):Thread miHilo = new MiClaseThread();miHilo.start();try {

miHilo.sleep(10000); } catch (InterruptedException e){}

Durante los 10 segundos que miHilo está dormido, incluso si el proceso se vuelve disponible, miHilo no se ejecuta. Después de 10 segundos, miHilo se convierte en "Ejecutable" de nuevo y, si el procesador está disponible se ejecuta. Para cada entrada en el estado "No Ejecutable", existe una ruta de escape distinto y específico que devuelve el thread al estado "Ejecutable". Por ejemplo, si un thread ha sido puesto a dormir durante un cierto número de milisegundos deben pasar esos milisegundos antes de volverse "Ejecutable" de nuevo. La siguiente es una secuencia de las acciones a realizar para cada entrada en el estado "No Ejecutable":Programación de Hilos: Ciclo de vida de un hilo 12 - 6Si se ha puesto a dormir un hilo, deben pasar el número de milisegundos especificados en sleep().Si se ha suspendido un hilo, se debe llamar a su método resume().Si un hilo está esperando una condición variable, siempre que el objeto propietario de la variable renuncie mediante notify() o notifyAll().Si un hilo está bloqueado durante la I/O, cuando se complete la I/O.

• Muerto: Un hilo pasa al estado de muerto cuando se termina su método run(), o cuando se ha invocado su método stop(). En algún momento el sistema dispondrá entonces del hilo muerto. Un hilo puede morir de dos formas:Muerte natural: se produce cuando su método run() sale normalmente. Por ejemplo, el bucle while en este método es un bucle que itera 100 veces y luego sale. Por tanto el hilo morirá naturalmente cuando se llegue al final de la iteración, es decir se termina su método run().public void run() {int i = 0;

while (i < 100) { i++; System.out.println("i = " + i);}

}Por muerte provocada: en cualquier momento llamando a su método stop(). El siguiente código crea y arranca miHilo luego lo pone a dormir durante 10 segundos. Cuando el thread actual se despierta, se lo mata con miHilo.stop(). El método stop() lanza un objeto ThreadDeath hacia al hilo a eliminar. El thread moririá cuando reciba realmente la excepción ThreadDeath.Thread miHilo = new MiClaseThread();miHilo.start();

Page 4: Tecnologias

try {Thread.currentThread().sleep(10000);

} catch (InterruptedException e){}miHilo.stop();El método stop() provoca una terminación súbita del método run() del hilo. Si el método run() estuviera realizando cálculos sensibles, stop() podría dejar el programa en un estado inconsistente. Normalmente, no se debería Programación de Hilos: Ciclo de vida de un hilo 12 – 7 llamar al método stop() pero si se debería proporcionar una terminación educada como la selección de una bandera que indique que el método run() debería salir. El método stop() se encuentra depreciado en la versión JDK1.2.1.

• Bloqueado: un hilo se encuentra en el estado bloqueado cuando el hilo realiza una solicitud de entrada/salida. Cuando termina la entrada/salida que estaba esperando, un hilo bloqueado queda en el estado listo.

2.2.2 Prioridades de un hilo.

Aunque un programa utilice varios threads y aparentemente estos se ejecuten simultáneamente, el sistema ejecuta una sola instrucción cada vez (esto es particularmente cierto en sistemas con una sola CPU), aunque realizado a velocidad suficiente para proporcionar la ilusión de simultaneidad. El mecanismo por el cual un sistema controla la ejecución concurrente de procesos se llama planificación (scheduling). Java soporta un mecanismo simple denominado planificación por prioridad fija (fixed priority scheduling). Esto significa que la planificación de los threads se realiza en base a la prioridad relativa de un thread frente a las prioridades de otros.

La prioridad de un thread es un valor entero (cuanto mayor es el número, mayor es la prioridad), que puede asignarse con el método setPriority. Por defecto la prioridad de un thread es igual a la del thread que lo creo. Cuando hay varios threads en condiciones de ser ejecutados (estado runnable), la máquina virtual elige el thread que tiene una prioridad mas alta, que se ejecutaran hasta que:

Un thread con una prioridad más alta está en condiciones de ser ejecutado (runnable), o

El thread termina (termina su metodo run), o Se detiene voluntariamente o  Alguna condición hace que el thread no sea ejecutable (runnable), como una

operación de entrada/salida o, si el sistema operativo tiene planificación por división de tiempos (time slicing), cuando expira el tiempo asignado.

Si dos o más threads están listos para ejecutarse y tienen la misma prioridad, la máquina virtual va cediendo control de forma cíclica (round-robin).

El hecho de que un thread con una prioridad más alta interrumpa a otro se denomina se denomina 'planificación con derecho preferente' (preemptive scheduling). 

Cuando un thread entra en ejecución y no cede voluntariamente el control para que puedan ejecutarse otros threads, se dice que es un thread egoísta (selfish thread). Algunos Sistemas Operativos, como Windows, combaten estas actitudes con una

Page 5: Tecnologias

estrategia de planificación por división de tiempos (time-slicing), que opera con threads de igual prioridad que compiten por la CPU. En estas condiciones el Sistema Operativo asigna tiempos a cada thread y va cediendo el control consecutivamente a todos los que compiten por el control de la CPU, impidiendo que uno de ellos se apropie del sistema durante un intervalo de tiempo prolongado.

Este mecanismo lo proporciona el sistema operativo, no Java. 

2.2.3 Sincronización de hilos.

Cuando se están utilizando hilos múltiples,algunas veces es necesario coordinar las actividades de dos o más. El proceso por el cual se logra esto se llama sincronización. La razón más común para la sincronización es cuando dos o mas hilos necesitan acceso a un recurso compartido que  sólo puede ser utilizado por un hilo a la vez. Otra razón para la sincronización es cuando un hilo está esperando un evento causado por otro hilo. En este caso, debe de haber algún medio por el cual el primer hilo se mantenga en estado suspendido hasta que el evento ocurra.     La sincronización esta soportada por la palabra clave synchronized y por unos cuantos métodos bien definidos que tienen todos los objetos.

USO DE MÉTODOS SYNCHRONIZED     Cuando se llama al método Synchronized , el hilo que llama ingresa al monitor de objeto, que entonces bloquea el objeto. Mientras esta bloqueado ningún otro hilo puede ingresar al método, ni ingresar algún otro método sincronizado definido por el objeto. Cuando el hilo retorna del método, el monitor desbloquea el objeto permitiendo que sea usado por el próximo hilo.

Los puntos clave de un método sincronizado son:

Un método sincronizado se crea precediendo su declaración con synchronized. Para cualquier objeto dado,una vez un método sincronizado ha sido llamado se

bloquea el objeto, y los métodos no sincronizados dentro del mismo objeto pueden ser utilizados por otros hilos en ejecución.

Otros hilos que traten de llamar un objeto sincronizado en uso ingresaría en un estado de espera, hasta que el objeto se desbloquea.

Cuando un hilo sale del método sincronizado, el objeto se desbloquea.

DECLARACIÓN SYNCHRONIZED    La creación del método Synchronized dentro de las clases creadas por nosotros mismos es fácil y eficiente sin embargo no trabaja en todos los casos. Por ejemplo, podemos querer sincronizar el acceso a algún método que no este modificado por Synchronized  ; esto ocurre cuando queremos utilizar una clase que no fue creada por nosotros sino por un tercero, y no tenemos acceso al código fuente.     La solución para este problema es poner llamadas a los métodos definidos por esa clase dentro de un bloque Synchronized. La forma general de un bloque  Synchronized es:

synchronized  (objeto){                                   //declaraciones para ser sincronizadas

                                                            }

Page 6: Tecnologias

     Aquí objeto hace referencia al objeto que va a ser sincronizado. Un objeto sincronizado asegura que una llamada a un método, ocurra solo después de que el hilo que llama ha ingresado al monitor del objeto.

EJEMPLO:/**

uso de synchronized en el control de accesos */class SumArray {          private int sum;

          synchronized int SumArray(int nums[]){           sum=0; //inicializa sum

           for (int i=0;i<nums.length;i++){               sum= nums[i];                System.out.println ("Ejecucion total para" + Thread.currentThread().getName() + " es " + sum);

          try{               Thread.sleep(10); //permite el suicheo de tareas          }         catch (InterruptedException exc){                  System.out.println ("Hilo principal interrumpido ");           }        }     return sum;  }    }class MyThread implements Runnable{                 Thread thrd;                 static  SumArray sa=new SumArray();                 int a[];                 int answer;

                / /contruye un nuevo hilo              MyThread(String name,int nums[]){                       thrd= new Thread (this,name);                       thrd.start(); //arranca el hilo                        a= nums;              }

             //inicia la ejecucion del nuevo hilo            public void run(){                       int sum;                       System.out.println ("Suma para " + thrd.getName() + " es " + answer);

Page 7: Tecnologias

                       System.out.println (thrd.getName() + "terminando");          }

}class Sync{          public static void main (String[] args) {          int a[]={1,2,3,4,5};

          MyThread mt1= new MyThread ("Hijo #1",a);          MyThread mt2= new MyThread ("Hijo #2",a);         }}

El programa anterior crea 3 clases. La primera es SumArray que contiene el método SumArray (), que suma un arreglo entero. La segunda clase es MyThread, que utiliza un objeto de tipo SumArray para obtener la suma de un arreglo entero. Finalmente, la clase Sync crea dos hilos, y permite que ellos calculen la suma de un arreglo entero.

    Dentro de sumArray (), se llama sleep() para permitir que ocurra un cambio de tarea, pero de hecho no es posible. Porque sumArray () está sincronizada. Solamente un hilo a la vez puede utilizarla. De modo que cuando el segundo hilo hijo comience su ejecución, no ingresa sumArray() hasta después que el primer hilo hijo esté terminado. Esto asegura que se produzca el resultado correcto. 

COMUNICACIÓN DE HILOS UTILIZANDO NOTIFY (), WAIT() Y NOTIFY ALL ()

     Los métodos wait (), notify () y notify all () son parte de todos los objetos porque están implementados por la clase Object. Estos métodos sólo pueden ser llamados desde el interior de un método Synchronized. A continuación se presenta como se utilizan. Cuando un hilo está temporalmente bloqueado para ejecución, llama a wait (). Esto hace que el hilo vaya a dormir y que el monitor para ese objeto se libere, permitiendo que otro hilo utilice el objeto. Luego en otro punto, el hilo dormido despierta cuando algún otro hilo ingresa al monitor, y llama a notify () o a notify All (). Un llamado a notify () reanuda el hilo. Una llamada a notify All () reanuda todos los hilos de más alta prioridad gana el acceso al objeto.          A continuación, se muestran varias formas de wait () definidas por Object:

final void wait() throws InterruptedException final void wait ( long milísegundos ) throws InterruptedException final void wait ( long milisegundos, int nanosegundos ) throwsInterrupted-Exception   

   La primera forma espera hasta que sea notificada. La segunda forma espera hasta que sea notificada o hasta que expire el período de milísegundos. La tercera forma le permite a usted especificar el período a aguardar en términos de nanosegundos.    A continuación, se muestran las formas generales de notify () y notify All ():

Page 8: Tecnologias

final void notify () final void notifyAll ()

EJEMPLO:    Para comprender la necesidad y aplicación de wait() y notify (), crearemos un programa que simule el tic-tac de un reloj, mostrando las palabras "tic" y "tac" en la pantalla. Para realizar esto, crearemos una clase llamada TickTock que contiene dos métodos: tick() y tock().    Paja ejecutar el reloj se crean dos hilos, uno que llama a tick () y otro, a tock (). El objetivo es hacer que los dos hilos se ejecute de modo que el resultado del programa presentes un "tic-tac" constante.

/* uso de wait () y notify () para crear un reloj de tarjeta. */class TickTock {      synchronized void tick ( boolean running ) {          if ( !running ) { //para el reloj                notify ( ); // notifica una espera para el hilo          return:         }            System.out.println ( "Tic ");          notify ( ); // permite la ejecución del tock ()          try {                wait ( ); // espera que tock ( ) se complete          }          catch ( InterruptedException exc ) {                System.out.println ( "del Hilo interrumpido  ");          }      }     synchronized void tock ( boolean running ) {               if (!running) { //para el reloj                     notify  ( ); // notifica una espera para el hilo               return;               }                System.out.println ( "Toc");               notify ( );               try {                      wait ( ); // espera que tick ( ) se complete               }               catch ( InterruotedException exc ) {                      System.out.println ( "Hilo interrumpido");               }     }}

class MyThread implements Runnable {         Thread thrd;         TickTock ttOb;

        // construye un nuevo hilo        MyThread ( String name.TickTock tt ) {                thrd= new Thread ( this.name );

Page 9: Tecnologias

                ttOb= tt;                thrd.start ( ); // arranca el hilo       }      //inicia la ejecución del nuevo hilo      public void main ( ) { // El hilo comienza a ejecutarse aquí              if ( thrd.getName ( ).compareTo ( "Tick") == 0 ) {                   for ( int i=0; i<5; i++ ) ttOb.tick ( true );                            ttOb.tock ( false );             }             else {                  for ( int i=0; i<5; i++ ) ttOb.tock ( true );                          ttOb.tock ( false );             }      }}

class ThreadCom {        public static void main ( String args [ ]) {                  TickTock t1= new TickTock ( );                  MyThread mt1= new MyThread ( "Tick",tt );                  MyThread mt2= new MyThread ( "Tock",tt );             try {                 mt1.thrd.join ( );                 mt2.thrd.join ( );           } catch ( InterruptedException exc ) {                     System.out.println ( "Procedimiento interrumpido ");          }     }}

2.2.4 Aplicaciones.

3 Aplicaciones de Clases e Interfaces Internas.

3.1 Clases Internas.

3.1.1 Definición de Clases.

una clase es una plantilla para la creación de objetos de datos según un modelo predefinido. Las clases se utilizan para representar entidades o conceptos, como los sustantivos en el lenguaje. Cada clase es un modelo que define un conjunto de variables -el estado, y métodos apropiados para operar con dichos datos -el comportamiento. Cada objeto creado a partir de la clase se denomina instancia de la clase.

Las clases son un pilar fundamental de la programación orientada a objetos. Permiten abstraer los datos y sus operaciones asociadas al modo de una caja negra. Los lenguajes de programación que soportan clases difieren sutilmente en su soporte para diversas

Page 10: Tecnologias

características relacionadas con clases. La mayoría soportan diversas formas de herencia. Muchos lenguajes también soportan características para proporcionar encapsulación, como especificadores de acceso.

Una clase también puede tener una representación (metaobjeto) en tiempo de ejecución, que proporciona apoyo en tiempo de ejecución para la manipulación de los metadatos relacionados con la clase.

3.1.2 Definición de Clase interna.

Las clases internas proveen un mecanismo que nos permite definir una clase dentro de

otra, así como una clase puede tener variables y métodos, también puede contener otras

clases.

Una clase interna se crea cuando deseamos que haya una estrecha relación entre 2

clases que contienen métodos específicos pero que están sumamente relacionados unos

con otros. Si se crea una clase interna, las variables y métodos de la clase dentro de la

cual se encuentran estarán disponibles dentro de la clase interna, incluso aquellos

marcados como privados(private).

3.1.3 Aplicaciones de Clases Internas.

Codificar un clase interna "Regular"::

Llamamos regular a aquella clase que no es:

1. Estática.2. Método local.3. Anónima.

Se define una clase interna dentro de las llaves de la clase externa, o sea, la clase que la

contiene. P. ej.:

class MiClaseExterna{class MiClaseInterna{ }}

Al compilar dicha clase obtendremos 2 archivos de clase:

* MiClaseExterna.class* MiClaseExterna$MiClaseInterna.class

Al final, la clase interna sigue siendo una clase separada de las demás, sin embargo, no

se puede acceder a ella como lo hacemos usualmente en la línea de comandos de esta

manera:

Page 11: Tecnologias

c:\> java MiClaseExterna$MiClaseInterna

Lo anterior no es posible debido a que una clase interna no tiene un método main ya que

una clase interna regular no puede tener declaraciones estáticas de ningún tipo. La única

manera de acceder a una clase interna es por medio de una instancia de la clase que la

contiene (la clase externa). En otras palabras, solamente en tiempo de ejecución.

¿Cómo utilizamos una clase interna?. Simple, pasemos al código.

public class ClaseExterna {private int x = 7;

//Definición de una clase internaclass MiClaseInterna{public void verClaseExterna(){System.out.println("El valor de X de la ClaseExterna es: "+ x);} }

public void crearInterna(){//Crear una instancia de la clase internaMiClaseInterna mci = new MiClaseInterna();mci.verClaseExterna();}

public static void main(String[] args){ ClaseExterna ce = new ClaseExterna();ce.crearInterna(); //Llamamos al método que crea la clase interna}

}

Analizando un poco lo que hemos hecho, nos damos cuenta de que accedemos a los

métodos de la clase interna SOLAMENTE a través de una instancia de la clase que la

contiene. La clase externa tiene un método (en este caso crearInterna()) que crea una

instancia de la clase interna a partir de otra instancia de la clase externa y posteriormente

en al misma función se manda a llamar el método verClaseExterna() que nos ayuda a

imprimir el valor actual de la variable privada x. Pero ¿cómo instanciamos una clase

interna fuera de la clase que la contiene?.

Crear un objeto de una clase interna fuera del código de instancia de la clase externa::

Page 12: Tecnologias

Supongamos que queremos utilizar un método de la clase interna fuera de la clase

externa, es decir, en una clase independiente. Sabemos de antemano que para poder

acceder a la clase interna necesitamos una instancia de la clase externa, entonces,

tomando en cuenta que la siguiente clase es independiente de la ClaseExterna creada

anteriormente pero que se encuentra en el mismo paquete y puede ser accedida sin

problemas, la manera de acceder a dicho método sería la siguiente:

public class ClasesInternas {public static void main (String[] args){ClaseExterna ce = new ClaseExterna();ClaseExterna.MiClaseInterna mci = ce.new MiClaseInterna();mci.verClaseExterna();}}

o en una línea...

public static void main(String[] args){ ClaseExterna.MiClaseInterna mci = new ClaseExterna().new MiClaseInterna();mci.verClaseExterna();}

Es una sintaxis simple pero que debemos memorizarla si queremos utilizar clases internas

en nuestras aplicaciones.

Referenciar una instancia de una clase interna o externa dentro de una clase interna::

De antemano sabemos (o debemos saber) que la manera en que un objeto hace

referencia hacia él mismo es mediante la referencia this. Revisemos un poco la

referencia this:

+ La palabra reservada this puede ser utilizada solamente dentro del código de instancia

de una clase y no dentro de código estático.

+ Al referenciar con this, hacemos referencia(valga la redundancia) al objeto que se está

ejecutando actualmente.

+ La referencia this es la manera en que un objeto puede pasarse a sí mismo como

parámetro hacia un método. P. ej.:

public void miMetodo(){MiClase mc = new MiClase();mc.hacerAlgo(this); //se pasa como parámetro el objeto actual.

Page 13: Tecnologias

}

Dentro de una clase interna, la referencia a this apunta hacia la instancia e la clase

interna, pero ¿cómo referenciamos a la clase externa desde la clase interna?, la

respuesta en el siguiente código:

public class ClaseExterna {private int x = 7;

//Definición de una clase internaclass MiClaseInterna{public void verClaseExterna(){System.out.println("El valor de X de la ClaseExterna es: "+ x);System.out.println("La referencia a la clase interna: "+ this);System.out.println("La referencia a la clase externa: "+ClaseExterna.this);} }

public void crearInterna(){//Crear una instancia de la clase internaMiClaseInterna mci = new MiClaseInterna();mci.verClaseExterna();}

public static void main(String[] args){ ClaseExterna.MiClaseInterna mci = new ClaseExterna().new MiClaseInterna();mci.verClaseExterna();} }

El resultado al ejecutar el código anterior es:

El valor de X de la ClaseExterna es: 7La referencia a la clase interna: ClaseExterna$MiClaseInterna@112f614La referencia a la clase externa: ClaseExterna@1d9dc39

Así que:+ Para referenciar una clase interna dentro de la clase interna se utiliza this.+ Para referenciar una clase externa dentro de la clase interna se utilizaNombreDeLaClaseExterna.this

Debido a que una clase interna es un miembro actual de la clase externa, se pueden

aplicar controles de acceso tal como lo hacemos con variables y métodos. Los

modificadores aplicables a clases internas son:

+ final+ abstract+ public

Page 14: Tecnologias

+ private+ protected+ static (lo que la volvería una clase anidada estática, no una clase interna)+ strictfp

3.2 Interfaces.

3.2.1 Definición de Interfaz.

Una interfaz es la descripción de uno o más servicios  (métodos) que posteriormente alguna clase puede implementar  (y por ende ofrecer).

Por ejemplo, si un alumno sabe alemán, tenemos idea de lo  que él es capaz. Además de ser persona (herencia) él cumple  la interfaz “interprete de alemán”. También podríamos decir que  él es un “interprete de alemán” (la misma relación que en  herencia).

Otro Ejemplo: si usted se entera que alguien es salvavidas, él  sabrá responder ante una emergencia en el agua. Por una parte está la descripción de qué sabe que hacer un salvavidas y por otro hay una persona que tiene esas “implementaciones” Lo mismo se puede pensar para personas que tienen  certificación Java.

3.2.2 Sintaxis para la implementación de interfaces.

Una clase que implementa una interfaz puede implementar explícitamente un miembro de esa interfaz. Cuando un miembro se implementa explícitamente, no es posible obtener acceso a él por medio de una instancia de clase, sino sólo a través de una instancia de la interfaz. Este tutorial contiene dos ejemplos. El primer ejemplo ilustra cómo implementar explícitamente miembros de interfaz y obtener acceso a ellos. El segundo ejemplo muestra cómo implementar dos interfaces que presentan los mismos nombres de miembro.

Ejemplo 1

Este ejemplo declara una interfaz IDimensions y una clase Box, la cual implementa explícitamente los miembros de la interfaz Length y Width. El acceso a los miembros se realiza a través de la instancia de interfaz myDimensions.

interface IDimensions

{

float Length();

float Width();

}

class Box : IDimensions

{

float lengthInches;

Page 15: Tecnologias

float widthInches;

public Box(float length, float width)

{

lengthInches = length;

widthInches = width;

}

float IDimensions.Length()

{

return lengthInches;

}

float IDimensions.Width()

{

return widthInches;

}

public static void Main()

{

Box myBox = new Box(30.0f, 20.0f);

IDimensions myDimensions = (IDimensions) myBox;

System.Console.WriteLine("Length: {0}", myDimensions.Length());

System.Console.WriteLine("Width: {0}", myDimensions.Width());

}

}

Resultado

Length: 30

Width: 20

Descripción del código

Observe que las siguientes líneas, en el método Main, están desactivadas mediante comentarios, ya que producirían errores de compilación. No se puede obtener acceso desde una instancia de clase a un miembro de interfaz implementado explícitamente:

//System.Console.WriteLine("Length: {0}", myBox.Length());

Page 16: Tecnologias

//System.Console.WriteLine("Width: {0}", myBox.Width());

Observe también que las siguientes líneas del método Main imprimen correctamente las dimensiones del cuadro, ya que los métodos se invocan desde una instancia de la interfaz:

System.Console.WriteLine("Length: {0}", myDimensions.Length());

System.Console.WriteLine("Width: {0}", myDimensions.Width());

3.2.3 Aplicaciones de interfaces.

4 Fundamentos de interfaces graficas de usuarios.

4.1 Conceptos básicos.

4.1.1 Definición de GUI.

La interfaz gráfica de usuario, conocida también como GUI (del inglés graphical user interface), es un programa informático que actúa de interfaz de usuario, utilizando un conjunto de imágenes y objetos gráficos para representar la información y acciones disponibles en la interfaz. Su principal uso, consiste en proporcionar un entorno visual sencillo para permitir la comunicación con el sistema operativo de una máquina o computador.

Habitualmente las acciones se realizan mediante manipulación directa, para facilitar la interacción del usuario con la computadora. Surge como evolución de las interfaces de línea de comandos que se usaban para operar los primeros sistemas operativos y es pieza fundamental en un entorno gráfico. Como ejemplos de interfaz gráfica de usuario, cabe citar los entornos de escritorio Windows, el X-Window de GNU/Linux o el de Mac OS X, Aqua.

En el contexto del proceso de interacción persona-computadora, la interfaz gráfica de usuario es el artefacto tecnológico de un sistema interactivo que posibilita, a través del uso y la representación del lenguaje visual, una interacción amigable con un sistema informático.

4.1.2 Elementos básicos de una GUI.

Llamamos Interfaz Gráfica GUI (Graphical User Interface) al conjunto de componentes gráficos que posibilitan la interacción entre el usuario y la aplicación. Es decir ventnas, botones, combos, listas, cajas de diálogo, campos de texto, etc.

Primero tenemos que diseñar la aplicación,programarla y por último los eventos que se generan a medida que el usuario interactua con la Interfaz.

Los componentes son objetos de las clases que heredan de la clase base componente como Button, List, TextField, TextArea, Label, etc.

En una GUI los componentes son contenidos en Contenedores o containers. Un Containes es un objeto cuya clase hereda de Container(clase que a su vez es subclase de Component) y tiene la responsabilidad de contener Componentes.

Page 17: Tecnologias

Generalmente una GUI se monta sobre un Frame. Esté sera el Container principal que contendrá a los componentes de la Interfaz Gráfica, un Container podría contener a otros containers.

Distribución de componentes (layouts)

Los containers contienen componentes y estos son acomodados dentro del espacio visual del container respetanto unaa cierta distribución que llamaremos layout.

AWT y Swing

Java provee dos API's con las que podemos trabajar para desarrollar GUIs, la más básica es AWT (Abstrct Window Toolkit). Las más desarrolladas se hacen con Swing, las cuales son más identificables ya que todas comienzan con "J", por ejemplo: JButton, JTextField, JTextArea, JPanel y JFrame son clases de Swing.

Todo el manejo de eventos y layouts es exactamente el mismo para AWT y Swing.

Distribuciones Relativas

Los layouts determinan el criterio con el que se vaan a distribuir los componentes dentro del container

FlowLayout : Distribuye los componentes uno al lado del otro en la parte superior del container. Por defecto provee una alineación centrada, pero también puede alinear a la izquierda o derecha.

BorderLayout: Divide el espacio del container en 5 regiones: NORTH, SOUTH, EAST, WEST y CENTER, admite un único componente por región

GridLayout: Divide el espacio del container en una grilla de n filas por m columnas, en donde las celdas son de igual tamaño

GridBagLayout: Divide el espacio del container en una grilla donde cada componente puede ocupar varias filas y columnas. Además permite distribuir el espacio interno de cada celda.

4.2 Implementación

4.2.1 Implementación de una GUI en java.

En Java, la ventana (llamada también Form en algunos toolkits), es llamada Frame, y forma parte del paquete java.awt. Por su parte, WindowListener forma parte de java.awt.event.

Veamos algunos métodos de Frame con un pequeño ejemplo.

import java.awt.Frame;

public class WinListener{

private Frame ventana;

Page 18: Tecnologias

public WinListener(){

ventana = new Frame("Muestra WindowListener");

ventana.setSize(640, 480);

ventana.setVisible(true);

}

public static void main(String[] args){

WinListener w = new WinListener();

}

}

Como ves, el código es relativamente corto.

Fíjate que la clase fue declarada como public, asi que el código anterior debe estar en un archivo llamado WinListener.java o no compilará.

Veamos de a poco.

ventana = new Frame(“Muestra WindowListener”) crea un nuevo Frame o ventana, con el título indicado. Este es uno de los constructores de Frame.

ventana.setSize(640, 480) da tamaño a la ventana. El primer número es su ancho, el segundo el alto; ambos números se refieren a pixeles.

ventana.setVisible(true) hace visible la ventana. En Java, crear una ventana no la hace visible inmediatamente. En próximos tutoriales veremos las ventajas de aquello.

Si ejecutas el código, te vas a encontrar con algo más o menos así:

También puedes notar que minimizar/maximizar la ventana funciona sin problemas, pero cerrar no produce absolutamente nada. ¿Qué es lo que pasa ahí? Pues simple: no hay un listener que haga algo con el evento cerrar ventana.

Ahora hace su entrada magistral el primer listener que estudiaremos: WindowListener. Como es una interfaz, debemos hacer una clase que lo implemente, es decir, que ponga código a los métodos que declara; WindowListener declara cinco métodos… pero basta de palabrerías. ¡Vamos al código!

import java.awt.Frame;

import java.awt.event.WindowListener;

import java.awt.event.WindowEvent;

public class WinListener{

private Frame ventana;

Page 19: Tecnologias

public WinListener(){

ventana = new Frame("Muestra WindowListener");

ventana.setSize(640, 480);

ventana.setVisible(true);

ventana.addWindowListener(new EscuchaVentana());

}

class EscuchaVentana implements WindowListener{

public void windowActivated(WindowEvent e){

System.out.println("windowActivated");

}

public void windowClosed(WindowEvent e){

System.out.println("windowClosed");

}

public void windowClosing(WindowEvent e){

System.out.println("windowClosing");

ventana.dispose();

}

public void windowDeactivated(WindowEvent e){

System.out.println("windowDeactivated");

}

public void windowDeiconified(WindowEvent e){

System.out.println("windowDeiconified");

}

public void windowIconified(WindowEvent e){

Page 20: Tecnologias

System.out.println("windowIconified");

}

public void windowOpened(WindowEvent e){

System.out.println("windowOpened");

}

}

public static void main(String[] args){

WinListener w = new WinListener();

}

}

El código de nuestro constructor no tiene modificaciones mayores, salvo su última línea: ventana.addWindowListener(new EscuchaVentana());

En esa línea es donde estamos registrando el WindowListener, es decir, lo estamos asociando con la ventana. Si te fijas, poco más abajo tenemos una clase llamada EscuchaVentana, que es una implementación del WindowListener y que nos permitirá realizar alguna operación en cada evento que se genere.

Para cada método, sólo he puesto código para que escriba en consola el nombre del método/evento generado, así que te recomiendo ejecutar tu código desde una consola/terminal/símbolo de sistema para que puedas apreciar lo que pasa con la ventana.

Y ahora si, nuestra ventana está totalmente operativa.

La clave para que se cierre está en el método windowClosing del listener. windowClosing es el evento que se genera cuando se intenta cerrar la ventana, es decir, cuando el usuario presiona la X de la esquina. Para que la ventana se cierre, esta debe ser liberada, es decir, llamar al método dispose() de la misma; si no se hace esto, el evento se genera, pero la ventana no se cierra.

Para los más avanzados en programación, habrán notado que EscuchaVentana es una clase contenida en WinListener, por lo que EscuchaVentana tiene acceso a los atributos de WinListener. ¿Y qué hubiera pasado si WinListener hubiera heredado de Frame? No podía haber dicho this.dispose() en windowClosing(), puesto que en ese contexto, this habría sido instancia de EscuchaVentana… Una forma alternativa de obtener la ventana sobre la que se generó el evento es con el método getWindow() de WindowEvent (fíjate que el parámetro de todos los métodos de WindowListener es un WindowEvent). Así que en el código podrías reemplazar perfectamente

ventana.dispose()

Page 21: Tecnologias

En el método windowClosing(), por…

e.getWindow().dispose()

obteniendo el mismo resultado en ambos casos.

Quienes tengan conocimientos más avanzados de Java, de seguro conocerán las clases anónimas, que es una clase que sólo tiene alcance dentro del ámbito en el cual se define. Son relativamente habituales justamente para implementar listener de GUI, y el código con una clase anónima quedaría más o menos así:

import java.awt.Frame;

import java.awt.event.WindowListener;

import java.awt.event.WindowEvent;

public class WinListener{

private Frame ventana;

public WinListener(){

ventana = new Frame("Muestra WindowListener");

ventana.setSize(640, 480);

ventana.setVisible(true);

ventana.addWindowListener(new WindowListener(){

public void windowActivated(WindowEvent e){}

public void windowClosed(WindowEvent e){}

public void windowDeactivated(WindowEvent e){}

public void windowDeiconified(WindowEvent e){}

public void windowIconified(WindowEvent e){}

public void windowOpened(WindowEvent e){}

public void windowClosing(WindowEvent e){

System.out.println("Cerrando ventana...");

e.getWindow().dispose();

}

});

}

public static void main(String[] args){

WinListener w = new WinListener();

Page 22: Tecnologias

}

}

En este caso, se está creando una implementación de WindowListener al vuelo, lo que te ahorra tener que crear una clase nueva exclusivamente para eso. También nota que ahora sólo puse código para el método windowClosing(), puesto que es el único que me interesa controlar para este ejemplo; el resto de métodos se queda sin cuerpo.

Es importante destacar en este punto que una clase anónima sólo tiene alcance en el punto donde se declara y que los métodos que implementa no son una expresión lambda (o closure), así que no caigas en la tentación. De todas maneras, una clase anónima siempre es una clase anidada, es decir, puede acceder a los atributos de la clase que la contiene.

4.2.2 Implementación de una GUI en C#.

En C#, el espacio de nombres y clases System.Windows.Forms de .NET Framework proporciona un completo conjunto de componentes para el desarrollo de formularios Windows Forms. Por ejemplo, el código siguiente utiliza Label, Button y MenuStrip.

Ejemplo de C#

Simplemente derive de la clase Form, del modo siguiente:

public partial class Form1 : System.Windows.Forms.Form

y agregue sus propios componentes:

this.button1 = new System.Windows.Forms.Button();

this.Controls.Add(this.button1);

En el código siguiente se muestra cómo agregar una etiqueta, un botón y un menú a un formulario.

namespace WindowsFormApp

{

public partial class Form1 : System.Windows.Forms.Form

{

private System.ComponentModel.Container components = null;

private System.Windows.Forms.Label label1;

private System.Windows.Forms.Button button1;

private System.Windows.Forms.MenuStrip menu1;

public Form1()

{

InitializeComponent();

Page 23: Tecnologias

}

private void InitializeComponent()

{

this.components = new System.ComponentModel.Container();

this.label1 = new System.Windows.Forms.Label();

this.Controls.Add(this.label1);

this.button1 = new System.Windows.Forms.Button();

this.Controls.Add(this.button1);

this.menu1 = new System.Windows.Forms.MenuStrip();

this.Controls.Add(this.menu1);

}

static void Main()

{

System.Windows.Forms.Application.Run(new Form1());

}

}

}

Al igual que en Java, en C# se puede registrar para escuchar un evento de un componente. Por ejemplo, cuando se presiona y suelta un botón, el motor en tiempo de ejecución envía un evento Click a cualquier agente de escucha que haya registrado un interés en el evento Click de este botón.

private void button1_Click(object sender, System.EventArgs e)

{

}

Puede utilizar el código siguiente a fin de registrar button1_Click para controlar el evento Click de una instancia de Button denominada button1.

// this code can go in InitializeComponent()

button1.Click += button1_Click;

Page 24: Tecnologias

5 Mapeo objeto relacional.

5.1 Conceptos básicos.

5.1.1 Justificación del mapeo objeto-relacional.

5.1.2 Alternativas al mapeo objeto-relacional.

5.2 Implementación.

5.2.1 Uso de motores de persistencia.