Anda di halaman 1dari 148

MODULO

Integración
de Programación
Prof. Martín Aguirre

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Índice Temático
Presentación 4
Historial del lenguaje Java y la plataforma SQL 4

Unidad I: Desarrollo de programas bajo entorno Java con Eclipse

1.1.1 Introducción y fundamentos de la POO 8


1.1.2 Paradigma 9
1.1.3 Variables (teoría y práctica) 12
1.1.4 Constantes (teoría y práctica) 14
1.1.5 Operadores (teoría y práctica) 17
1.1.6 Clases (teoría y práctica) 33
1.1.7 Métodos 39
1.1.8 Estructuras (teoría y práctica) 42

1.2.1 Instalación y configuración JAVA Eclipse (guía práctica) 49


1.2.2 Herencia (teoría y práctica) 50
1.2.3 Arreglos (teoría y práctica) 56
1.2.4 Poliformismos (teoría y práctica) 59
1.2.5 Encapsulamiento (teoría y práctica) 61

1.3.1 Proyectos (teoría y práctica) 64


1.3.2 Importación de librerías (teoría y práctica) 73
1.3.3 Almacenamiento en archivos (teoría y práctica) 78
1.3.4 Diagnóstico y excepciones (teoría y práctica) 84

Unidad II: Desarrollo de bases de datos en SQL con MySQL

2.1.1 Introducción en Bases de datos y SQL 97


2.1.2 Desarrollo e implementación de bases de datos 99

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
2.1.3 Instalación y configuración de plataforma MySQL (guía práctica) 108
2.1.4 Conexión de base de dato con aplicación en JAVA 113
2.1.5 Lenguaje SQL. Definiciones y uso (teoría y práctica) 115
2.1.6 Consultas y reportes (teoría y práctica) 123

Unidad III: Desarrollo de interfaz e implementación - Proyecto final

3.1.1 Introducción al desarrollo visual como interfaz de usuario 126


3.1.2 Desarrollo e implementación de interfaz 127
3.1.3 Estandarización de interfaces 131
3.1.4 Verificación y validaciones para el correcto funcionamiento 132

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
PRESENTACIÓN

Desde hace ya décadas, muchos teóricos aseveran que estamos siendo


testigos de la tercera revolución industrial, la misma se sustenta en las tecnologías
informáticas y las telecomunicaciones principalmente.

Si reflexionamos en los grandes cambios / avances logrados en la última


década en las distintas ciencias, es imposible obviar que en algún momento fueron
beneficiadas a través de la ciencia de la informática y las comunicaciones. Es tan
así que el presente se ha dispuesto tan dinámico y avasallador que, cuando uno
adquiere un bien o servicio, en ese mismo instante ya es tan parte del pasado que
quedará obsoleto en el muy corto plazo.

En un mundo globalizado, adaptarse a los cambios, a los nuevos


paradigmas, y con ello en nuevas plataformas y entornos de software es crucial e
indispensable en el mundo de la Informática; Dado que estar actualizados en
materia de software y nuevas tecnologías será cada vez más crucial para un
desarrollador de aplicaciones.

Por ende, les propongo durante la cursada desarrollar los conocimientos y


habilidades para poder trabajar en el software (JAVA) y bases de datos (SQL),
siendo esto de sustancial valor para vuestro desarrollo profesional en el futuro.

Programación Orientada a Objetos: Historia

Si bien es de público conocimiento el gran avance sobre el terreno de la


programación cómo se posicionó la Programación Orientada a Objetos (POO a
partir de ahora) no es un tema nuevo. Fue a finales de los años 60 cuando éste
nuevo paradigma fue concebido. Uno de los grandes problemas que surgían
consistía en la necesidad de adaptar el software a nuevos requisitos imposibles de
haber sido planificados inicialmente. Este alto grado de planificación y previsión es
contrario a la propia realidad. El hombre aprende y crea a través de la
experimentación. La Orientación a Objetos brinda estos métodos de
experimentación, no exige la planificación de un proyecto por completo antes de
escribir la primera línea de código.
4

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Esto mismo pensaron en 1967, Krinsten Nygaard y Ole-Johan Dahl de la
Universidad de Oslo, en el Centro Noruego de Computación, donde se dedicaban
a desarrollar sistemas informáticos que realizaban simulaciones de sistemas
mecánicos, por ejemplo motores, para analizar su rendimiento. En este desarrollo
se encontraban con dos dificultades, por un lado los programas eran muy
complejos y, por otro, forzosamente tenían que ser modificados constantemente.

Este segundo punto era especialmente problemático; ya que la razón


de ser de los programas era el cambio y no sólo se requerían varias
iteraciones para obtener un producto con el rendimiento deseado, sino que
muchas veces se querían obtener diversas alternativas viables, cada una
con sus ventajas e inconvenientes.

La solución que idearon fue diseñar el programa paralelamente al objeto


físico. Es decir, si el objeto físico tenía un número x de componentes, el programa
también tendría x módulos, uno por cada pieza. Dividiendo el programa de esta
manera, había una total correspondencia entre el sistema físico y el sistema
informático. Así, cada pieza física tenía su abstracción informática en un módulo.
De la misma manera que los sistemas físicos se comunican enviándose señales,
los módulos informáticos se comunicarían enviándose mensajes. Para llevar a la
práctica estas ideas, crearon un lenguaje llamado Simula 67.

Este enfoque resolvió los dos problemas planteados. Primero, ofrecía una
forma natural de dividir un programa muy complejo y, en segundo lugar, el
mantenimiento pasaba a ser controlable. El primer punto es obvio. Al dividir el
programa en unidades informáticas paralelas a las físicas, la descomposición es
automática. El segundo punto también se resuelve. En cada iteración de
simulación, el analista querrá cambiar o bien piezas enteras o bien el
comportamiento de alguna pieza. En ambos casos la localización de los cambios
está perfectamente clara y su alcance se reduce a un componente, siempre y
cuando la interfaz del mismo no cambie. Por ejemplo, si se estuviese simulando el
motor de un coche, puede que se quisiera modificar el una característica utilizada
en la simulación anterior. Si la nueva característica tuviera la misma interfaz
(mismas entradas y salidas) o se cambiase sólo su comportamiento interno, nada
del sistema (aparte de la propia característica) estaría afectado por el cambio.

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
El siguiente paso se da en los años 70 en los Estados Unidos, más
concretamente en el Centro de Investigación de Palo Alto (PARC), California,
donde Xerox tiene un centro de investigación en el que los científicos trabajan en
conceptos que puedan convertirse en productos industriales al cabo de 10 a 20
años. En aquellos años contrataron a un joven llamado Alan Kay, que venía de la
Universidad de Utah, donde había estado trabajando con gráficos, y había
examinado un nuevo compilador procedente de Noruega, llamado Simula. Kay
encontró conceptos, que más tarde aprovechó en Xerox, para llevar a término las
ideas que proponía en su tesis doctoral. Éstas consistían básicamente en la
propuesta de construcción de un ordenador llamado Dynabook, adecuado para ser
utilizado por niños. El ordenador no tenía teclado, la pantalla era sensible al tacto y
la mayor parte de la comunicación era gráfica. Al desarrollar este proyecto se
inventaron el mouse y los entornos gráficos. Al volver a encontrarse en Palo Alto
con una programación compleja y experimental, como en el caso de Nygaard y
Dahl, Kay, junto con Adele Goldberg y Daniel Ingalls, decidieron crear un lenguaje
llamado SmallTalk. Este lenguaje de programación es considerado el primer
lenguaje Orientado a Objetos puro, dónde todo lo que se crea son clases y
objetos, incluyendo las variables de tipos más simples. La primera versión se
conoció como Smalltalk-72, aunque fueron surgiendo nuevas versiones (76,80,..)
que pasaron de ser desarrolladas sólo para máquinas Xerox a serlo para la
mayoría de plataformas disponibles.

Hasta este momento, uno de los defectos más graves de la


programación era que las variables eran visibles desde cualquier parte del
código y podían ser modificadas incluyendo la posibilidad de cambiar su
contenido (no existen niveles de usuarios o de seguridad, o lo que se conoce
como visibilidad). D. Parnas fue quien propuso la disciplina de ocultar la
información. Su idea era encapsular cada una de las variables globales de la
aplicación en un sólo módulo junto con sus operaciones asociadas, de forma que
sólo se podía tener acceso a estas variables a través de sus operaciones
asociadas. El resto de los módulos (objetos) podían acceder a las variables sólo
de forma indirecta mediante las operaciones diseñadas para tal efecto.

Con la reutilización como pilar básico de su filosofía, un equipo de


Sun Microsystems crea Java en 1995, con el objetivo de conquistar el mundo
de la programación, teniendo gran éxito en aplicaciones en red. No en vano,
captó mucha atención en los primeros meses de 1996 en base a ser considerado
6

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
el medio para dominar Internet. Java es totalmente orientado a objetos. Está
basado en C++, intentando evitar los principales problemas del mismo, como, por
ejemplo, el acceso directo a memoria dinámica. Se fundamenta en el uso de
bytecode (código de bajo nivel, portable e interpretable) y una máquina virtual
accesible para todo el mundo que ejecuta esos bytecodes. Hoy en día es lo más
cercano a lo que podría denominarse una máquina universal.

El mundo de los lenguajes de programación orientados a objeto evoluciona


día a día y, continuamente, surgen nuevos lenguajes o nuevas versiones de
lenguajes ya consolidados.

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
UNIDAD I

1.1.1 Introducción y fundamentos de la POO

Tal como lo mencionamos en la presentación, el mundo del desarrollo de


software está sometido a un proceso de constante de evolución. Podemos
observar el avance en función del tiempo nombrando a algunos de los lenguajes
que hicieron historia:

• El código máquina
• El ensamblador
• Conceptos como la programación procedural
• La programación estructurada
• La programación lógica
• Programación orientada a objetos, siendo éste el paradigma más extendido
hoy en día.

Tal como surgió en su momento el paradigma de Programación


Estructurada para intentar paliar las deficiencias de la programación en ese
momento, también la Programación Orientada a Objetos apareció como una
evolución natural en los paradigmas de programación que busca solucionar los
principales problemas del paradigma anterior. Un breve resumen de las
deficiencias que este nuevo paradigma intenta resolver serían los siguientes:

• Distinta abstracción del mundo. La programación clásica se centra en el


comportamiento, normalmente representado por verbos, mientras que
nuestra mente se centra en los seres, a los que, normalmente, identificamos
con sustantivos.

• Dificultad en modificación y actualización. Los programas suelen tener


datos compartidos por varios subprogramas, esto puede provocar que
cualquier ligera modificación en un módulo afecte indirectamente al resto.

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
• Dificultad en mantenimiento. Es complicado encontrar todos los errores
en grandes aplicaciones, lo que origina que muchos no aparezcan hasta
estar la aplicación en funcionamiento.

• Dificultad en reutilización. Normalmente las subrutinas son demasiado


dependientes del contexto de un programa como para poder aprovecharlas
en un nuevo programa.

A la hora de afrontar la construcción de grandes aplicaciones, estos


defectos pueden provocar que muchos proyectos sean inabordables. La
Programación Orientada a Objetos surgió con el objetivo de erradicar los
problemas expuestos.

1.1.2 Paradigma

¿Qué es un paradigma de programación?

Brevemente y según la definición clásica podemos decir que: Un paradigma


de programación es una colección de modelos conceptuales que juntos modelan
el proceso de diseño y determinan, al final, la estructura de un programa. Dicho de
otro modo, un paradigma engloba un nuevo modelo / forma innovadora de resolver
un problema que en la actualidad no pueden ser resueltos y que es posible
implementarla como nueva solución a los futuros planteos que surjan.

Ahora bien, dentro del mundo del desarrollo de código, también podemos
en Wikipedia: “Un paradigma de programación es una propuesta tecnológica
adoptada por una comunidad de programadores y desarrolladores cuyo núcleo
central es incuestionable en cuanto que únicamente trata de resolver uno o varios
problemas claramente delimitados; la resolución de estos problemas debe suponer
consecuentemente un avance significativo en al menos un parámetro que afecte a
la ingeniería de software.

Un paradigma de programación representa un enfoque particular o filosofía


para diseñar soluciones. Los paradigmas difieren unos de otros, en los conceptos
y la forma de abstraer los elementos involucrados en un problema, así como en
los pasos que integran su solución del problema, en otras palabras, el cómputo.
9

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Tiene una estrecha relación con la formalización de determinados lenguajes
en su momento de definición. Es un estilo de programación empleado.

Un paradigma de programación está delimitado en el tiempo en cuanto a


aceptación y uso, porque nuevos paradigmas aportan nuevas o mejores
soluciones que la sustituyen parcial o totalmente.

El paradigma de programación que actualmente es el más utilizado es la


"orientación a objetos" (OO). El núcleo central de este paradigma es la unión de
datos y procesamiento en una entidad llamada "objeto", relacionable a su vez con
otras entidades "objeto".

Tradicionalmente, datos y procesamiento se han separado en áreas


diferente del diseño y la implementación de software. Esto provocó que grandes
desarrollos tuvieran problemas de fiabilidad, mantenimiento, adaptación a los
cambios y escalabilidad. Con la OO y características como el encapsulado,
polimorfismo o la herencia, se permitió un avance significativo en el desarrollo de
software a cualquier escala de producción. La OO parece estar ligada en sus
orígenes con lenguajes como Lisp y Simula, aunque el primero que acuñó el título
de "programación orientada a objetos" fue Smalltalk”.

Asimismo, dentro de los nuevos cambios y avances en lo que refiere a


tecnología, es posible nombrar a otro importante paradigma que surgió luego de
POO. El mismo de conoce como SOA o Arquitectura Orientada al Servicio
(Service Oriented Architecture). En éste caso en particular y teniendo en cuenta
que dentro del mundo de las ventas los servicios representan aproximadamente el
70% del total, éste nuevo paradigma está orientado exclusivamente a
SERVICIOS. La base es POO, pero se le suma XML o Lenguaje de marcas
extensible (Xtensible Markup Language) junto con una serie de pequeñas mejoras,
para llegar a lo que conoce como WEB SERVICES.

Programación Orientada a Objetos:

La programación orientada a objetos es una “filosofía”, un modelo de


programación, con su teoría y su metodología, que conviene conocer y estudiar
antes de nada. Un lenguaje orientado a objetos es un lenguaje de programación
que permite el diseño de aplicaciones orientadas a objetos. Dicho esto, lo normal
10

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
es que toda persona que vaya a desarrollar aplicaciones orientadas a objetos
aprenda primero la “filosofía” (o adquiera la forma de pensar) y después el
lenguaje, dado que “filosofía” sólo hay una y lenguajes muchos.

En resumen, éste nuevo paradigma y su evolución puede resumir sus


avances en:

• Conceptos de clase y objeto, que proporcionan una abstracción del mundo


centrada en los seres y no en los verbos.

• Los datos aparecen encapsulados dentro del concepto de clase. El acceso


a los datos se produce de manera controlada e independiente de la
representación final de los mismos.

Como consecuencia, se facilita el mantenimiento y la evolución de los


sistemas, al desaparecer las dependencias entre distintas partes del sistema.

Mediante conceptos como la composición, herencia y polimorfismo, que


iremos desarrollando en el transcurso de la cursada, se conseguirá simplificar el
desarrollo de sistemas. La composición y la herencia nos permiten construir clases
a partir de otras clases, aumentando en gran medida la reutilización.

Es muy importante destacar que cuando hacemos referencia a la


programación orientada a objetos no estamos hablando de unas cuantas
características nuevas añadidas a un lenguaje de programación. Estamos
hablando de una nueva forma de pensar acerca del proceso de descomposición
de problemas y de desarrollo de soluciones de programación.

La programación orientada a objetos surge en la historia como un intento


para dominar la complejidad que, de forma innata, posee el software.
Tradicionalmente, la forma de enfrentarse a esta complejidad ha sido
empleando lo que llamamos programación estructurada, que consiste en
descomponer el problema objeto de resolución en subproblemas y más
subproblemas hasta llegar a acciones muy simples y fáciles de codificar. Se trata
de descomponer el problema en acciones, en verbos.

11

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
La programación orientada a objetos es otra forma de descomponer
problemas. Este nuevo método de descomposición es la descomposición en
objetos; vamos a fijarnos no en lo que hay que hacer en el problema, sino en
cuál es el escenario real del mismo, y vamos a intentar simular ese escenario
en nuestro programa.

Los lenguajes de programación tradicionales no orientados a objetos, como


C, Pascal, BASIC, o Modula-2, basan su funcionamiento en el concepto de
procedimiento o función. Una función es simplemente un conjunto de instrucciones
que operan sobre unos argumentos y producen un resultado. De este modo, un
programa no es más que una sucesión de llamadas a funciones, ya sean éstas del
sistema operativo, proporcionadas por el propio lenguaje, o desarrolladas por el
mismo usuario.

1.1.3 Variables (teoría y práctica)

¿Qué son las variables?

Tal como su nombre lo indica son elementos / entidades que es posible


variar su contenido en función del tiempo.

Al momento de comenzar a desarrollar un programa, siempre


comenzamos por comprender cuál es el problema y de qué forma podremos
darle solución. Justo en medio del proceso es en donde surge el concepto
de las entidades; Las mismas las podremos nombrar como agentes u
objetos, las que contienen propiedades / atributos, y sus lazos de unión con
el exterior denominados métodos. Y, al igual que todo sistema, sus lazos
serán los que transporten los mensajes (información) generando un círculo
de acción y reacción entre las entidades/objetos.

12

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
El principio de desarrollo de una POO se encuentra sencilla y
directamente asociado a la teoría sistémica, sus entidades, características /
propiedades, límites del sistema y lazos de interacción con el exterior. A
partir de dicha teoría podremos obtener un paralelismo y en función de ello
poder poner en funcionamiento un desarrollo en POO.

Variables

En Java se conoce como variable a todo colaborador interno (variables de


instancia y de clase), externos (parámetros) y a los nombres locales en los
métodos (variables locales). Existen algunas reglas para nombrar a las variables:

• El primer carácter debe ser una letra, el guión bajo (_) o el signo de dólar
($, aunque está reservado).
• Puede estar seguido de letras, números, el guión bajo o el signo dólar.
• No hay límite para la longitud del nombre.
• No debe ser una palabra clave.

Es importante asignar los nombres de las variables de forma tal que el


propio nombre represente el dato que contienen. Si el nombre es una serie de
palabras, la primera letra de las palabras van en mayúscula (diaDelMes), esto es
una convención.

AL igual que en otros lenguajes, una variable se define especificando


primero su tipo y luego su nombre. Asimismo, se le pueden aplicar modificadores
como final, que hace que la referencia o el valor (se indica antes del tipo)
solamente se pueda asignar una vez.

Expresiones

Una expresión es una combinación de variables, operadores y envíos de


mensajes que evalúan un valor. El tipo del valor dependerá de los tipos de los
elementos involucrados. Veamos un ejemplo.

13

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
peso = persona.getPeso()

Aquí tenemos varias expresiones, primero tenemos persona, una expresión


que devuelve el objeto referenciado; luego el envío del mensaje getPeso a
persona, que devuelve un double; finalmente, la asignación es otra expresión que
devuelve el valor que se le asigna a peso y el tipo es del tipo de la variable.

1.1.4 Constantes (teoría y práctica)

¿Qué es una constante?

Una constante es una característica de una entidad. Se utiliza


principalmente para poder asignar un valor específico que se utiliza varias veces a
lo largo de un algoritmo, y que el mismo siempre mantiene su valor fijo.

Por ejemplo, dentro del desarrollo de un algoritmo que realiza cálculos de


fuerza con ecuaciones en los que interviene la gravedad; Es más sencillo generar
una constante que se llame “gravedad” cargándole en valor 9,81 que estar
copiando decena de veces el mismo valor, siento también más difícil comprender
el algoritmo al no estar identificado correctamente una vez que haya pasado un
tiempo y uno de haya olvidado.

Palabras clase STATIC Y FINAL (constantes)

Tal como mencionamos en el párrafo anterior, en los programas que


generemos usualmente intervendrán constantes: valores matemáticos como la
gravedad, o valores propios de programa que nunca cambian. Si nunca cambian,
lo adecuado será declararlos como constantes en lugar de variables. Supongamos
que queremos usar una constante como el valor de la gravedad y que usamos
esta declaración:

14

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
public class CaidaLibre {

private double Gravedad = 9.81;


public void mostrarConstanteGravedad () { System.out.println
(Gravedad); }
… desarrollo del resto del algoritmo…
}

Si creas un objeto de tipo caidaLibre, comprobarás que puedes invocar el


método mostrarConstanteGravedad para que te muestre el valor por pantalla.
No obstante, una declaración de este tipo presenta varios problemas. En primer
lugar, lo declarado no funciona realmente como constante, sino como variable con
un valor inicial. Prueba a establecer this.Gravedad = 9.81; dentro del método y
verás que es posible, porque lo declarado es una variable, no una constante. En
segundo lugar, cada vez que creamos un objeto de tipo calculadora estamos
usando un espacio de memoria para almacenar el valor 9.81. Así, si
tuviéramos diez objetos calculadora, tendríamos diez espacios de memoria
ocupados con la misma información, lo cual resulta ineficiente. Para resolver estos
problemas, podemos declarar constantes en Java usando esta sintaxis:

CaracterPublico/Privado static final TipoDeLaConstante = valorDeLaConstante;

En esta declaración intervienen dos palabras clave cuyo significado es importante:

a) static: los atributos miembros de una clase pueden ser atributos de clase o
atributos de instancia; se dice que son atributos de clase si se usa la
palabra clave static: en ese caso la variable es única para todas las
instancias (objetos) de la clase (ocupa un único lugar en memoria). A veces a
las variables de clase se les llama variables estáticas. Si no se usa static, el
sistema crea un lugar nuevo para esa variable con cada instancia (la variable
es diferente para cada objeto). En el caso de una constante no tiene sentido
crear un nuevo lugar de memoria por cada objeto de una clase que se cree.
Por ello es adecuado el uso de la palabra clave static. Cuando usamos “static
15

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
final” se dice que creamos una constante de clase, un atributo común a todos
los objetos de esa clase.

b) final: en este contexto indica que una variable es de tipo constante: no admitirá
cambios después de su declaración y asignación de valor “final” determina
que un atributo no puede ser sobrescrito o redefinido. O sea: no funcionará
como una variable “tradicional”, sino como una constante. Toda constante
declarada con final ha de ser inicializada en el mismo momento de declararla.
“final” también se usa como palabra clave en otro contexto: una clase final
(final) es aquella que no puede tener clases que la hereden.

Cuando se declaran constantes es muy frecuente que los programadores


usen letras mayúsculas (como práctica habitual que permite una mayor claridad en
el código), aunque no es obligatorio.

Una declaración en cabecera de una clase como private final double


Gravedad = 9.81; podríamos interpretarla como una constante de objeto. Cada
objeto tendrá su espacio de memoria con un contenido invariable.

Una declaración en cabecera de una clase como private static final


double Gravedad = 9.81; la interpretamos como una constante de clase. Existe
un único espacio de memoria, compartido por todos los objetos de la clase, que
contiene un valor invariable.

Ejemplos de uso:

private static final float Gravedad = 9.81f;


private static double Gravedad = 9.81;
public static final String passwd = "claveDeAcceso";
public static final int PrecioDeVenta = 100;

16

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Tal como ya lo hemos mencionado, cuando usamos la palabra clave static
la declaración de la constante ha de realizarse obligatoriamente en cabecera de
la clase, junto a los campos (debajo de la signatura de clase). Es decir, un atributo
de clase hemos de declararlo en cabecera de clase. Si tratamos de incorporarlo en
un método obtendremos un error. Por tanto dentro del método main (que es un
método de clase al llevar incorporado static en su declaración) no podemos
declarar constantes de clase. Por otro lado, final sí puede ser usado dentro de
métodos y también dentro de un método main. Por ejemplo, una declaración como
final String clave = “ClaveDeAcceso” es válida dentro de un método.

En resumen: en cabecera de clase usaremos static final para definir


aquellas variables comunes a todos los objetos de una clase.

Modifica el código de la clase CaidaLibre que vimos anteriormente para


declarar Gravedad como una constante de clase. Luego, intenta modificar el valor
de Gravedad usando una invocación como this.Gravedad =10;. Comprobarás
que se produce un error al compilar ya que los valores de las constantes no son
modificables.

1.1.5 Operadores (teoría y práctica)

Bloques

Un bloque es una secuencia de sentencias encerradas entre llaves y/o


paréntesis ({ …. }) y puede ser usado en cualquier lugar donde va una sentencia
(ya que un bloque es un sentencia). Los bloques en general se utilizan como el
cuerpo de las estructuras (como los ciclos) aunque también se los puede utilizar
solos, ya que definen un alcance léxico para los nombres. Esto quiere decir que se
puede redefinir una variable en un bloque, así el código del bloque accede a esta y
el código fuera del bloque accede a la primera definición.

Las estructuras son construcciones puramente sintácticas que se traducen


en funcionalidad, y alivian el trabajo del programador a la hora de poder realizar
agrupaciones de procesos.

17

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
If / Else / Else if

Esta es una de las estructuras de control de flujo más básicas dentro de los
lenguajes de programación. Permite, en base a una condición, modificar el flujo de
ejecución y se utiliza para situaciones como “si sucede algo entonces se toma una
decisión; si no sucede, se toma otra decisión”.

Representa una bifurcación, la toma de decisión donde solo hay dos


opciones, si sí o si no. A continuación veamos cómo se escribe:


If (Condicion) Entonces
Accion 1()
Else
Accion 2()

En el ciclo if se evalúa la condición booleana que se encuentra entre los


paréntesis y en base al resultado se ejecutan las acciones que se encuentran en
el cuerpo de if (en caso de true / verdadero). Si no, continúa con la ejecución
ignorando el if.

Si queremos que se ejecute un código en el caso de false / falso


(manteniendo el caso de true / verdadero), utilizamos la etiqueta else después
del cuerpo de if, seguido de un bloque de código. Siempre es mejor y más claro
poner la opción más frecuente como bloque if ya que es lo primero otra persona
va a leer.

If (haceFrio()) {// Caso verdadero

meAbrigo();

// al finalizar continúa en A
} else { // Caso falso
noMeAbrig();

18

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016

// al finalizar continúa en A
}
// A

Finalmente, podemos encadenar varios if utilizando else if(<condición>), de


acuerdo a nuestras necesidades (teoría de anidamiento).

Switch

Debemos tener en cuenta que esta


estructura de control de flujo nos permite
realizar la comparación de un tipo numérico
entero y carácter primitivo contra varios
candidatos que deseemos y que de esta
forma podremos ejecutar el código en
consecuencia.

19

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
La forma de escribirlo es presentada a continuación:

switch(<valor>) {
case <literal>: <codigo> break;
case <literal>: <codigo> break;

default: <codigo> break;
}

Al switch le pasamos un valor para comparar, luego, en cada caso, lo


comparamos contra un literal del mismo tipo y, en caso de ser iguales, se ejecuta
el código asociado. Se pone la etiqueta break al final del código de cada caso
para poder finalizar la ejecución del switch (generalmente es lo deseado), si no se
seguirían ejecutando en cascada el resto de los códigos del switch (generalmente
es un bug). El caso default se ejecuta cuando ninguno de los casos coincidió.

int opcion = 2;
switch (opcion) {
case 1: …
// código para el caso 1
// sin break, continúa ejecutando el caso 2
case 2: …
// código para el caso 2
break;
// continúa en A
default: …
// código para cuando no es ni 1 ni 2
break;
// continúa en A

}

// A

20

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Ciclo For

El ciclo for es una de las estructuras más usadas en los lenguajes de


programación. Consta de cuatro partes: la inicialización, la condición, el paso
siguiente y el cuerpo del ciclo. Veamos cómo se ve esto en Java.

int sum = 0;
for(int i = 0; i < 4; i++) {
sum += i;
}

El fragmento de código anterior suma los números


0, 1, 2 y 3 en la variable sum. La primera línea es la
declaración e inicialización de la variable sum en 0.
Luego tenemos el ciclo for donde podemos apreciar la
inicialización (int i = 0) dónde declaramos otra variable.
Esta variable solo puede ser accedida por el código for.
Separada por un punto y coma tenemos la condición (i <
4), que dice si la variable i es menor a 4. Después,
también separado por un punto y coma, encontramos el
paso siguiente (i++) que en este caso dice “incrementar
en 1 la variable i”.

El cuerpo del for es el código comprendido entre


las llaves. En él encontramos la sentencia sum += i; que
es igual a escribir sum = sum + i;, o sea, sumar lo que
hay en sum con lo que hay en i y el resultado guardarlo
en sum. La semántica de for es la siguiente: “para i igual
a 0, mientras i sea menor que 4, sumar sum e i y
guardarlo en sum, luego incrementar i en 1 y repetir”.
Formalmente, la estructura del for acepta cualquier
sentencia válida de Java como inicialización (incluso
nada) y se ejecuta solamente una vez al inicio del for.
Acepta cualquier sentencia que dé como resultado un
valor boolean como condición (nada significa true) que
21

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
se pregunta al inicio de cada iteración (paso o ciclo) y ejecuta el código si el
resultado es true e interrumpe el for si es false. Finalmente, cualquier expresión
válida para el paso siguiente, que se ejecuta al final de cada ejecución del código
del cuerpo. Dentro del cuerpo del ciclo es posible utilizar las etiquetas break y
continúe para alterar el comportamiento de este. La etiqueta break se usa para
abortar la ejecución del for completamente, en cambio, la etiqueta continúe se
utiliza para terminar la ejecución de la iteración actual y ejecutar la siguiente.
Veamos un ejemplo:

int sum = 0;
for (int i = 0; i < 4; i++) {
if (i == 1) continue; // si i es igual a 1 ir al paso siguiente
if (i == 3) break; // si i es igual a 3 abortar el for
sum += i;
}
assertEquals (sum, 2);

Ciclo While

Debemos tener en cuenta que el ciclo while es más simple que for dado
que solamente tiene la condición y el cuerpo. De esta forma, un ciclo while que
sume los números del 0 al 3 se ve así:

int sum = 0;
int i = 0;
while (i < 4) {
sum += i;
i++;
}

22

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Como vemos en el bloque de
código anterior, si nos encargamos de
realizar la comparación con el
correspondiente al del ciclo for, tenemos
la inicialización fuera de la estructura de
while y el incremento de la variable i se
encuentra dentro del cuerpo. A while hay
que leerlo de esta forma: mientras se
cumpla la condición, ejecutar el cuerpo.
Como en el for, y en todas las otras
estructuras de ciclos, podemos utilizar las
etiquetas break y continúe.

Ciclo Do While

El ciclo do while es una variación del ciclo while, donde primero se ejecuta
el cuerpo y posteriormente se pregunta si se cumple la condición para continuar
iterando o no, veamos un ejemplo:

int sum = 0;
int i = 0;
do {
sum += i;
i++;
} while (i < 4);

Hay que ser cuidadosos a la hora de usar esta estructura, porque el cuerpo
se ejecuta sí o sí al menos una vez. Por esta razón debemos ser muy cuidadosos
si estamos trabajando en u proyecto agregamos un ciclo while, y posteriormente
decidimos transformarlo en un do while ya que podemos tener dificultades.

23

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Ciclo For Each

Este ciclo sirve para recorrer estructuras


tales como listas y otras colecciones de objetos.
Estas estructuras se conocen como iterables y
responden al mensaje iterator que devuelve una
instancia de Iterator, que es un objeto que sabe
cómo recorrer la estructura. El for each es una
variación del for para ser usada con estas
estructuras iterables:

// asumamos que dígitos es una colección con


los números del 0 al 9...

int sum = 0;
for (int digito : digitos) {
}
assertEquals(sum, 45);
sum += digito;

Leemos este código de esta forma: por


cada digito en digitos, sumar sum con digito y
guardarlo en sum.

Realmente esta estructura es lo que se


conoce como syntax sugar (endulzar la sintaxis,
dado que no agrega funcionalidad, solamente
facilidad en el uso de algo que ya estaba) del for
común, como vemos en el siguiente fragmento de
código.
24

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
int sum = 0;
for (Iterator i = digitos.iterator; i.hasNext (); ) {
int digito = ((Integer) i.next ()).intValue ();
sum += digito;
}
assertEquals (sum, 45);

Como podemos observar, el programador tiene que escribir más código (y


por lo tanto, con mayor posibilidad de cometer errores) y es menos legible que la
versión del for each. Esta es la traducción del for each al for que realiza el
compilador Java y que hasta la versión 1.5 los programadores tenían que
escribir. En la inicialización se crea una variable del tipo Iterator y se la asigna con
el iterador de la colección de los dígitos. La condición pregunta si existe un
próximo elemento que visitar, si existe otro dígito. El paso siguiente se encuentra
vacío dado que lo realizaremos en el cuerpo con el envío del mensaje next al
iterador. En el cuerpo conseguimos el siguiente elemento con next y se lo
asignamos a la variable dígito (la que creamos en cada paso del for each) y
realizamos la suma que corresponde. Notar que forzamos el resultado de next a
int con la instrucción Integer y el mensaje intValue. Lo primero se conoce como
casteo donde le indicamos a la JVM que sabemos el tipo real del objeto y
queremos usarlo (next devuelve un Object y no se puede asignar directamente a
int). Lo segundo Java lo hace automáticamente en el caso del for each y se
conoce como auto boxing (envolver y desenvolver un dato primitivo en su clase
asociada).

Desarrollo de un Thread:

¿Qué es un Thread?

En esencia el concepto de la multitarea nos permite ejecutar varios


procesos a la vez; es decir, de forma concurrente y por tanto eso nos permite
hacer programas que se ejecuten en menor tiempo y sean más eficientes.

25

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Evidentemente no podemos ejecutar infinitos procesos de forma
concurrente ya que el hardware tiene sus limitaciones, pero raro es a día de hoy
los ordenadores que no tengan más de un núcleo por tanto en un procesador con
dos núcleos se podrían ejecutar dos procesos a la vez y así nuestro programa
utilizaría al máximo los recursos
ecursos hardware. Para que puedan ver más gráficamente
la diferencia en un par de imágenes, supongamos que tenemos un programa
secuencial en el que se han de ejecutar 4 procesos; uno d detrás
etrás de otro, y estos
tardan unos segundos:

Si en vez de hacerlo de forma secuencial, lo hiciésemos con 4 hilos, el


programa tardaría en ejecutarse solo 20 segundos, es decir el tiempo que tardaría
en ejecutarse el proceso más largo. Esto evidentemente sería lo ideal, pero la
realidad es que no todo se puede paralelizar y hay que saber el número de
procesos en paralelo que podemos lanzar de forma eficiente. En principio en esta
entrada no vamos a hablar sobre ello ya que e ell objetivo de la misma es ver cómo
c
se utilizan los hilos en java con un ejemplo relativamente sencillo y didáctico.

26

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
En Java para utilizar la multitarea debemos de usar la clase Thread (es
decir que la clase que implementemos debe heredar de la clase Thread) y la clase
Thread implementa la Interface Runnable. No es la intención de éste punto poder
hacer desarrollos multitareas, pero sí que puedan lograr entender el concepto y
darse una idea de cuándo se debe aplicar.

Synchronize (palabra reservada)

La palabra reservada synchronized se usa para indicar que ciertas partes


del código, (habitualmente, una función miembro) están sincronizadas, es decir,
que solamente un subproceso puede acceder a dicho método a la vez.

Cada método sincronizado posee una especie de llave que puede cerrar o
abrir la puerta de acceso. Cuando un subproceso intenta acceder al método
sincronizado mirará a ver si la llave está echada, en cuyo caso no podrá
accederlo. Si método no tiene puesta la llave entonces el subproceso puede
acceder a dicho código sincronizado.

Las siguientes porciones de código son ejemplos de uso del modificador


synchronized

Object key = new Object();



// este código puede ser ejecutado en paralelo por varios threads
synchonize(key) {

// este no
}

Ahora bien, una vez aclarado, sí podemos verlo como una estructura de
sincronización de threads. Esto se usa para asegurarse de que un solo thread está
ejecutando el código del bloque asociado. Para ello se utiliza un objeto a modo de
llave, solamente un único thread puede tener la llave en un momento dado. El
27

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
thread que tiene la llave es el que puede ejecutar. El resto espera hasta que se
libere la llave.

Tipos primitivos y literales

Si bien Java es un lenguaje orientado a objetos, posee valores que no son


objetos. Estos elementos son los llamados tipos primitivos. Los tipos primitivos son
los representantes de los números y los caracteres que debido a problemas en la
performance de las primeras versiones de Java, se decidió que no sean objetos.
Son valores bien conocidos por la máquina virtual y cuyas operaciones están
cableadas en ella. Esto presenta un desafío para el programador dado que tiene
que lidiar con objetos y con los tipos primitivos. Al no ser objetos (no ser
referenciados) no se les puede asignar null, ni utilizar en lugar de cualquier
objeto. No son instancia de ninguna clase, no tienen métodos ni responden a
mensajes. Solo se pueden realizar operaciones sobre ellos como la suma y resta,
y otras que están definidas por el lenguaje directamente.

Para tratar de salvar un poco estos problemas, Java introduce clases que
envuelven a los tipos primitivos en objetos que, además, incluyen algunos
métodos para transformar del tipo primitivo a texto y viceversa. Los tipos primitivos
son:

• boolean: representa a los valores verdadero y falso de la lógica de Bool.


Los valores de este tipo son true(verdadero) y false(falso). La clase
asociada con este tipo primitivo es Boolean.

boolean verdadero = true;

• byte: se encarga de representar a los números de 8 bits entre -128 y 127.


La clase asociada es la denominada Byte.

byte eñe = 164; // el ascii de la ñ

28

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
“Recordemos que en el lenguaje de programación Java los números enteros se
pueden escribir tanto en decimal (164) como en octal (0244) y en hexadecimal
(0xA4 o 0xa4)”.

• char: es el tipo que representa a un carácter Unicode (16 bits). La clase


asociada es Character. Los literales de carácter en Java se escriben entre
comillas simples, y aceptan un carácter o el código Unicode. También
aceptan un número.

char eñeCaracter = ‘ñ’;


char eñeNumero = 241; // código unicode decimal
char eñeUnicode = ‘\u00F1’;

“Para caracteres como el retorno de carro y la sangría, Java tiene unos códigos
especiales que sirven también para las cadenas de texto, se les dice caracteres
escapados”.

char lineaNueva = ‘\n’;


char comillaSimple = ‘\’’;
char comillaDoble = ‘\”’;
char lineaNueva = ‘\n’;
char sangria = ‘\t’;
char barraInvertida = ‘\\’;

• double: es el tipo de los números de punto flotante de 64 bits de precisión


definidos en el estándar IEEE 754.

• Double. Los literales se pueden escribir con los decimales (usando el punto
como separador) o en notación científica.

double unValor = 123.4;


double otroValor = 1.234e2; // mismo valor pero en notación científica
doublé yOtroMas = 123.4d; // especifico que es doublé el literal

29

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
• float: similar al double pero de 32 bits de precisión, su clase asociada es
Float. Los literales se pueden escribir como los de double (sin la d) aunque
ahí podríamos tener un problema al transformar un double literal a un float,
lo mejor es especificar que es un literal de float usando la f.

float literal = 123.4f;

• int: se encarga de representar los números de 32 bits enteros, que se


encuentran entre los valores -2147483648 y 2147483647. Su clase
asociada es Integer. Los literales se pueden escribir de la misma forma que
los literales de byte.

• long: representa los números de 64 bits, entre -9223372036854775808 y


9223372036854775807. Su clase asociada es Long. Sabemos que los
literales se pueden escribir en decimal, octal o también en hexadecimal.

• short: representa los de números de 16 bits, entre -32768 y 32767. Su


clase asociada es Short. Los literales se pueden escribir de la misma forma
que los literales de long.

• String: si bien String no es un tipo primitivo, ya que es una clase, la


incluimos en este apartado dado que el lenguaje da soporte para manejar
las cadenas de caracteres de forma similar a un dato primitivo. En los
literales aplican también las reglas de de escape vistas para los char y se
crean utilizando la comillas dobles (“”).

String texto = “hola mundo”;

• Arrays: los arrays (arreglos) son colecciones indexadas de elementos de


tamaño fijo y establecido en el momento de creación. El acceso a los
elementos de un array está dado por un índice que va desde 0 hasta la

30

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
posición n-1, donde n es la longitud del array. Los arrays son instancias de
la clase Array. Los arrays se pueden crear de la siguiente manera:

String [] unArray = new String[4]; // un array con 4 posiciones vacías


String [] otroArray = new String [] {“a”, “b”} //

“El acceso a los elementos de los arrays se realiza con el operador [] y un índice
entero, podemos ver la forma correcta de realizar esta operación en el siguiente
bloque de código”.

assertEquals(otroArray[0], “a”);
otroArray[0] = “c”;
assertEquals(otroArray[0], “c”);
otroArray[10] = “error”; // arroja una excepción de tipo
ArrayIndexOutOfBOundException

Operadores matemáticos

Java permite operar sobre los tipos numéricos primitivos, usando los
conocidos operadores matemáticos más algunos otros. Estos operadores realizan
funciones que están cableadas en la máquina virtual de Java y no son envíos de
mensajes. Los operadores son:

Operadores aritméticos

• +, -, /, *: suma, resta, división, multiplicación.


• %: módulo.
• -: negación de un número.

El operador + también sirve para concatenar varias String.

31

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Operadores lógicos

• &, &&, |, ||, ^, !: y, y (short circuit), o inclusivo, o inclusivo (short circuit), o


exclusivo, que corresponde a negación.

• ==, !=: igualdad, desigualdad. Estos operadores evalúan la igualdad de


tipos primitivos, 4 == 3 + 1 da como resultado true; o de referencias para
los objetos, si una variable hace referencia al mismo objeto. No verifica que
dos objetos sean iguales (que se puedan intercambiar), eso se verifica
enviando el mensaje equals a un objeto mediante el envío del objeto para
comparar.

• <, <=, >, >=: menor, menor o igual, mayor, mayor o igual. Sirven para
comparar valores numéricos primitivos entre sí.

“Los operadores de short circuit se utilizan cuando no queremos evaluar la


segunda parte de la condición, cuando con el resultado de la primera parte es
suficiente para saber el resultado general”.

Operadores de bit

• &, |, ^: y, o inclusivo y o exclusivo. Operan sobre los bits que conforman los
tipos primitivos.

• ~: complemento bit. Invierte los bits de un valor.

• <<, >>, >>>: operadores de corrimiento de bits. Mueven los bits hacia la
izquierda o derecha, tantos bits como se indiquen. En la práctica es igual a
multiplicar o dividir por 2 (mantienen el signo, salvo >>>).

Otros Operadores

• ++, --: incrementar o disminuir en 1 una variable de tipo numérica entera


(byte, short, int y long). Puede ser tanto sufijo como prefijo, en el primer
32

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
caso, primero se modifica el valor y luego se lo lee; en el segundo, se lee y
luego se modifica. Son operadores unarios.

• =: asignación, se utiliza para asignar un valor a una variable. Devuelve el


valor asignado.

• ?:: operador ternario, recordemos que se utiliza como forma corta de la


estructura que corresponde a if/else.

• instanceof: operador que chequea si un objeto es instancia de una


determinada clase (se consideran también las superclases).

1.1.6 Clases (teoría y práctica)

¿Qué es una clase?

Podemos encontrar cientos de miles de definiciones dentro de la WEB.


Ahora bien, la forma más sencilla de poder comprender de qué estamos hablando
es llevarlo a la comparación mental. Imaginémonos que deseamos hacer un
castillo de arena hecho de cilindros con dos formas distintas, una con el borde
redondo y la otra en forma de serrucho. ¿Cómo logramos eso? Con simplemente
un balde y dos formas para su extremo. Dentro de nuestra asociación, llamemos
balde a la clase y objetos a nuestros cilindros. También podemos decir que esas
formas distintas que poseen en los extremos se llaman características de los
mismos. Y ahí ya tenemos nuestra definición terminada. – Una clase es un
modelo, un molde del cual obtendremos nuestros objetos con sus características.
Al analizar qué objeto deseamos obtener, es justamente ahí cuando deberemos
hacer foco en la creación de la clase. Ahora ya con una base previa, pasaremos a
las definiciones formales…

Al definir una clase, se lo hace en función de su forma y del comportamiento


de los objetos que crea, llamados instancias. La clase es la unidad mínima de
código válida que requiere Java, aquí o existe código fuera de una de ellas.

33

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Según Wikipedia, también podemos decir que …

“En informática, 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 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.”

Ya hemos visto algunos ejemplos, ahora entenderemos en profundidad


cada elemento de su definición. Todo archivo fuente Java requiere que exista una
clase pública con el mismo nombre. A continuación tenemos el caso más simple
de una clase:

public class Auto {


...
}

Indicamos que es pública con el modificador public, luego viene el class y


finalmente el nombre. Por defecto, toda clase hereda de Object, pero si queremos
heredar de alguna otra, podemos especificarlo a continuación del nombre
utilizando la palabra extends seguida del nombre de la clase padre.

public class Auto extends Vehiculo {


...
}

34

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Solamente se puede heredar de una clase, recordemos que Java
implementa herencia simple. Para tratar de alivianar esta restricción, Java utiliza
las interfaces para definir protocolos homogéneos a través de jerarquías
heterogéneas. Las veremos más adelante, pero para decir que una clase
implementa una interfaz (o varias), escribimos el nombre de esta (en el caso de
ser varias, separados por comas) después de la palabra implements.

public class Auto extends Vehiculo implements VehiculoTerrestre {


...
}

La clase principal del


archivo debe ser pública o no
debe indicarse nada
(visibilidad por defecto,
llamada de paquete), no
puede ser privada. Las clases
con la visibilidad de paquete
solamente pueden ser
utilizadas por otras clases
que estén dentro del mismo
paquete.
Las clases públicas
pueden ser utilizadas por
cualquier otra clase y también
pueden ser marcadas como
finales, utilizando el modificador final antes del class en la definición. Este
modificador hace que no pueda existir una subclase de ella.

35

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Finalmente, las clases pueden ser marcadas como abstractas (moldes
para otras clases) usando el modificador abstract.. Las clases abstractas, como
veremos más adelante en detalle, no pueden tener instancias y sirven para
agrupar el conocimiento y comportamiento en común de las subclases de este
tipo.

Tengamos en cuenta que en Java las clases son instancia de la clase


Class,, en ella están definidos los mensajes que entiende cada clase, como el tipo
de mensajes que entienden sus instancias o qué constructores tienen, entre
muchas otras cosas. Para acceder a la instancia de Class correspondiente a una
clase podemos utilizar el nombre seguido de .class o podemos pedírsela a una
instancia mediante el mensaje getClass(). Ambas formas devuelven un objeto de
tipo Class que es el dato que nos interesa.

36

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Atributos

Los colaboradores internos, también conocidos como variables de instancia


o atributos, se definen en el cuerpo de la clase. Su definición es similar a la de
cualquier variable, con la particularidad que se le puede agregar los modificadores
de visibilidad.

Siempre definamos los atributos como privados, dado que son detalles
de implementación que deberían estar siempre ocultos a los demás objetos
(incluso a aquellos pertenecientes a alguna subclase). Cuando queremos exponer
un atributo como público, deberíamos hacerlo a través de métodos getter (lectura)
y setter (escritura). Existe la convención de nombrar a estos métodos utilizando
los prefijos get, set o is, seguido del atributo.

public class Auto {


private Marca marca;

public Marca getMarca() {
return marca;
}
public void setMarca(Marca marca) {
this.marca = marca;
}

}

37

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Las variables tipo boolean utilizan el prefijo is en vez del get.

public boolean isEmpty() {…}


public void setEmpty(boolean isEmpty) {…}

Esta es sólo una convención Java, pero no quiere decir que sea obligatoria.
Reflexionemos acerca del significado de un método que setea si un objeto está
vacío o no. ¿No tendría que ser, por ejemplo, vaciar()? ¿Y lo contrario, llenar()?
Siempre pensemos en el significado que queremos darle a los métodos en el
contexto de uso.

Supongamos que tenemos un objeto Empleado cuyo sueldo está


representado por el atributo público sueldo. Cada vez que queramos obtener un
dato del tipo sueldo estaremos accediendo al atributo.

Ahora supongamos que tenemos un cambio, y el sueldo, en vez de ser un


valor fijo, depende de ciertos porcentajes variables. El sueldo tiene que ser
calculado cada vez que se lo quiere leer. Tendremos que cambiar absolutamente
todos los lugares donde se estaba leyendo el atributo sueldo por el envío de
mensaje sueldo(). No solamente por la adaptabilidad al cambio, sino también por
la flexibilidad que da enviar un mensaje (ya que se decide en runtime por method
lookup), es que debemos siempre enviar mensajes en vez de acceder
directamente a un atributo, incluso dentro del código de la misma clase.

Las variables pueden ser inicializadas junto con su definición.

public class Auto {


private Marca marca; // inicializado al valor por defecto (null)
private String modelo = “”; // inicializado

}

38

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
En los métodos de la clase, estos atributos son accedidos directamente con
su nombre o utilizando el pseudo variable this que es una referencia al objeto
actual.

Los atributos estáticos, aquellos que pertenecen a la clase, se definen


agregando el modificador static. Estos atributos pueden ser accedidos por medio
de su nombre o utilizando el nombre de la clase más el nombre del atributo.

Cuando heredamos de una clase, heredamos los atributos definidos por


ella, aunque no podamos acceder a ellos ya que podrían estar declarados como
privados. Si estamos creando una jerarquía, es una buena práctica no definir
atributos hasta que no lleguemos a las clases concretas (opuesto a lo abstracto; si
consideramos que las clases abstractas están en lo alto de la jerarquía, las clases
concretas estarían abajo). Si lo hiciéramos estaríamos forzando una
implementación particular y concreta en vez de una necesidad abstracta.
Deberíamos declarar métodos abstractos (protected o public, dependiendo de la
finalidad). Así las clases concretas pueden decidir ellas mismas que
implementación quieren y necesitan.

1.1.7 Métodos

¿Qué es un método?

En la programación , un método es una subrutina cuyo código es definido


en una clase y puede pertenecer tanto a una clase, como es el caso de los
métodos de clase o estáticos, como a un objeto, como es el caso de los
métodos de instancia. Análogamente a los procedimientos en los lenguajes
imperativos, un método consiste generalmente de una serie de sentencias para
llevar a cabo una acción, un juego de parámetros de entrada que regularán dicha
acción o, posiblemente, un valor de salida (o valor de retorno) de algún tipo.

La diferencia entre un procedimiento (generalmente llamado función si


devuelve un valor) y un método es que éste último, al estar asociado con un objeto
o clase en particular, puede acceder y modificar los datos privados del objeto
correspondiente de forma tal que sea consistente con el comportamiento deseado
para el mismo. Así, es recomendable entender a un método no como una
secuencia de instrucciones sino como la forma en que el objeto es útil (el
39

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
método para hacer su trabajo). Por lo tanto, podemos considerar al método
como el pedido a un objeto para que realice una tarea determinada o como la vía
para enviar un mensaje al objeto y que éste reaccione acorde a dicho mensaje.

Definición de libro

Los métodos son la implementación asociada a un mensaje que entiende el


objeto. Su definición consta de una firma que sirve para identificar al método,
seguido del código. La firma o signatura de un método se forma con los
modificadores de visibilidad, seguido de otros posibles modificadores (final, native,
synchronized, static y etcétera); luego viene el tipo de respuesta (o void si no
responde nada), el nombre (que sigue las reglas de los nombres de variables) y,
finalmente, los argumentos que espera. Los argumentos se definen como
variables (tipo seguido del nombre) con la posibilidad de aplicar el modificador
final.

class Auto {

public Marca getMarca() {
return this.marca;
}
public void arrancarCon(final Llave laLlave) throws
LlaveIncorrectaException
{…}

}

Si un método lanza excepciones, ya sea porque su propio código las lanza


o no las atrapa, debe especificarlas como parte de la firma del mensaje e
indicarlas luego de los argumentos utilizando la palabra throws seguido de los
nombres de estas separados por coma. Java permite que los mensajes tengan
argumentos variables, por ejemplo si queremos pasar un cierto número de
parámetros en un envío y cierto número en otro, y queremos que además sea
invocado el mismo método. En Java podemos hacer esto así:

40

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
void cargarEquipaje(Equipaje … equipajes) {

}

Y el envío de mensaje se realiza de la siguiente forma.


auto.cargarEquipaje(unEquipaje, otroEquipaje, yOtroEquipajeMas);

Recordemos que se coloca la cantidad deseada de parámetros separados


por comas. Esto es en realidad una facilidad del compilador que transforma el
código de la siguiente forma:

void cargarEquipaje(Equipaje [] equipajes) {



}

auto.cargarEquipaje(new Equipaje[] {unEquipaje, otroEquipaje,
yOtroEquipajeMas});

Sí, transforma todo del mismo modo que si el mensaje recibiera un array y
en el código del método accediéramos a los argumentos utilizando el parámetro
como un array.

void cargarEquipaje(Equipaje … equipajes) {


for(Equipaje equipaje : equipajes) {
this.cargar(equipaje);
}
}
41

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Java permite que se puedan definir varios métodos con el mismo nombre
dentro de una misma clase. Esto se conoce como sobrecarga (overloading). La
restricción que existe es que lo métodos difieran en la cantidad o tipo de
argumentos que reciben.

void acelerarA (int kmPorH) {…} // válido


void acelerarA (double kmPorH) {…} // válido
void acelerarA (int km, int h) {…} // válido
bool acelerarA (int kmPorH) {…} // inválido

El compilador se encarga de decidir cuál mensaje se envía en base a la


información de tipos y de cantidad de parámetros que se pasan.

1.1.8 Estructuras (teoría y práctica)

¿Qué es la estructura en POO?

Hablamos de estructura a las relaciones, propiedades y métodos como


componentes que se emplean para poder desarrollar una Programación Orientada
a Objetos.

Tal como hemos dicho, un objeto puede considerarse como una especie de
cápsula dividida en tres partes: Relaciones, Propiedades y Métodos que iremos
desarrollando a continuación. Cada uno de estos componentes desempeña un
papel totalmente independiente:

Las relaciones permiten que el objeto se inserte en la organización y están


formadas esencialmente por punteros a otros objetos.

Las propiedades distinguen un objeto determinado de los restantes que


forman parte de la misma organización y tiene valores que dependen de la
propiedad de que se trate. Las propiedades de un objeto pueden ser heredadas a
sus descendientes en la organización.
42

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Los métodos son las operaciones que pueden realizarse sobre el objeto,
que normalmente estarán incorporados en forma de programas (código) que el
objeto es capaz de ejecutar y que también pone a disposición de sus
descendientes a través de la herencia.

Encapsulamiento y ocultación

Como hemos visto, cada objeto es una estructura compleja en cuyo interior
hay datos y programas, todos ellos relacionados entre sí, como si estuvieran
encerrados conjuntamente en una cápsula. Esta propiedad (encapsulamiento),
es una de las características fundamentales en la POO.

Existe la posibilidad de que los objetos sean inaccesibles, e impedir que


otros objetos, los usuarios, o incluso los programadores conozcan cómo está
distribuida la información o qué información hay disponible. Esta propiedad de los
objetos se denomina ocultación de la información.

Esto no quiere decir, sin embargo, que sea imposible conocer lo necesario
respecto a un objeto y a lo que contiene. Si así fuera no se podría hacer gran cosa
con él. Lo que sucede es que las peticiones de información a un objeto deben
realizarse a través de mensajes dirigidos a él, con la orden de realizar la
operación pertinente. La respuesta a estas órdenes será la información requerida,
siempre que el objeto considere que quien envía el mensaje está autorizado para
obtenerla.

El hecho de que cada objeto sea una cápsula facilita enormemente que un
objeto determinado pueda ser transportado a otro punto de la organización, o
incluso a otra organización totalmente diferente que precise de él. Si el objeto ha
sido bien construido, sus métodos seguirán funcionando en el nuevo entorno sin
problemas. Esta cualidad hace que la POO sea muy apta para la reutilización de
programas.

43

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Organización de los objetos

En principio, los objetos forman siempre una organización jerárquica, en el


sentido de que ciertos objetos son superiores a otros de cierto modo.

Existen varios tipos de jerarquías: serán simples cuando su estructura


pueda ser representada por medio de un "árbol". En otros casos puede ser más
compleja.

En cualquier caso, sea la estructura simple o compleja, podrán distinguirse


en ella tres niveles de objetos.

- La raíz de la jerarquía. Se trata de un objeto único y especial. Este se


caracteriza por estar en el nivel más alto de la estructura y suele recibir un nombre
muy genérico, que indica su categoría especial, como por ejemplo Objeto Madre,
Raíz o Entidad.

- Los objetos intermedios. Son aquellos que descienden directamente de la raíz


y que a su vez tienen descendientes. Representan conjuntos o clases de objetos,
que pueden ser muy generales o muy especializados, según la aplicación.
Normalmente reciben nombres genéricos que denotan al conjunto de objetos que
representan, por ejemplo, Ventana, Cuenta, Fichero. En un conjunto reciben el
nombre de clases o tipos si descienden de otra clase o subclase.

- Los objetos terminales. Son todos aquellos que descienden de una clase o
subclase y no tienen descendientes. Suelen llamarse casos particulares,
instancias o ítems porque representan los elementos del conjunto representado
por la clase o subclase a la que pertenecen.

Veamos ahora en detalle los tres elementos mencionados en "Estructura de


un Objeto".

1. Relaciones

Las relaciones entre objetos son, precisamente, los enlaces que permiten a
un objeto relacionarse con aquellos que forman parte de la misma organización.
Las hay de dos tipos fundamentales:

44

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Relaciones jerárquicas. Son esenciales para la existencia misma de la
aplicación porque la construyen. Son bidireccionales, es decir, un objeto es padre
de otro cuando el primer objeto se encuentra situado inmediatamente encima del
segundo en la organización en la que ambos forman parte; asimismo, si un objeto
es padre de otro, el segundo es hijo del primero.

Una organización jerárquica simple puede definirse como aquella en la


que un objeto puede tener un solo padre, mientras que en una organización
jerárquica compleja un hijo puede tener varios padres).

Relaciones semánticas. Se refieren a las relaciones que no tienen nada


que ver con la organización de la que forman parte los objetos que las establecen.
Sus propiedades y consecuencia solo dependen de los objetos en sí mismos (de
su significado) y no de su posición en la organización.

Se puede ver mejor con un ejemplo: supongamos que vamos a construir un


diccionario informatizado que permita al usuario obtener la definición de una
palabra cualquiera. Supongamos que, en dicho diccionario, las palabras son
objetos y que la organización jerárquica es la que proviene de forma natural de la
estructura de nuestros conocimientos sobre el mundo.

La raíz del diccionario podría llamarse Temas. De éste término genérico


descenderán tres grandes ramas de objetos llamadas Vida, Mundo y Hombre. El
primero (Vida) comprenderá las ciencias biológicas: Biología y Medicina. El
segundo (Mundo), las ciencias de la naturaleza inerte: las Matemáticas, la Física,
la Química y la Geología. El tercero (Hombre) comprenderá las ciencias humanas:
la Geografía, la Historia, etc.

Veamos un ejemplo: estableceremos la relación trabajo entre los objetos


Newton y Óptica y la interpretaremos diciendo que significa que Newton trabajó en
óptica. La relación es, evidentemente, semántica, pues no establece ninguna
connotación jerárquica entre Newton y Óptica y su interpretación depende
exclusivamente del significado de ambos objetos.

La existencia de esta relación nos permitirá responder a preguntas como:

¿Quién trabajó en óptica? ¿En qué trabajó Newton? ¿Quien trabajó en Física?

45

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Las dos primeras preguntas se deducen inmediatamente de la existencia de
la relación trabajo. Para la tercera observamos que si Newton trabajó en óptica
automáticamente sabemos que trabajó en Física, por ser óptica una rama de la
Física (en nuestro diccionario, el objeto Óptica es hijo del objeto Física). Entonces
gracias a la POO podemos responder a la tercera pregunta sin necesidad de
establecer una relación entre Newton y Física, apoyándonos sólo en la relación
definida entre Newton y Óptica y en que Óptica es hijo de Física. De este modo se
elimina toda redundancia innecesaria y la cantidad de información que tendremos
que definir para todo el diccionario será mínima.

2. Propiedades

Todo objeto puede tener cierto número de propiedades, cada una de las
cuales tendrá, a su vez, uno o varios valores. En POO, las propiedades
corresponden a las clásicas "variables" de la programación estructurada. Son, por
lo tanto, datos encapsulados dentro del objeto, junto con los métodos (programas)
y las relaciones (punteros a otros objetos). Las propiedades de un objeto pueden
tener un valor único o pueden contener un conjunto de valores más o menos
estructurados (matrices, vectores, listas, etc.). Además, los valores pueden ser de
cualquier tipo (numérico, alfabético, etc.) si el sistema de programación lo permite.

Pero existe una diferencia con las "variables", y es que las propiedades se
pueden heredar de unos objetos a otros. En consecuencia, un objeto puede tener
una propiedad de maneras diferentes:

-Propiedades propias. Están formadas dentro de la cápsula del objeto.

-Propiedades heredadas. Están definidas en un objeto diferente, antepasado de


éste (padre, "abuelo", etc.). A veces estas propiedades se llaman propiedades
miembro porque el objeto las posee por el mero hecho de ser miembro de una
clase.

46

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
3. Métodos

Una operación que realiza acceso a los datos. Podemos definir método
como un programa procedimental o procedural escrito en cualquier lenguaje, que
está asociado a un objeto determinado y cuya ejecución sólo puede
desencadenarse a través de un mensaje recibido por éste o por sus
descendientes.

Son sinónimos de método todos aquellos términos que se han aplicado


tradicionalmente a los programas, como procedimiento, función, rutina, etc. Sin
embargo, es conveniente utilizar el término 'método' para que se distingan
claramente las propiedades especiales que adquiere un programa en el entorno
POO, que afectan fundamentalmente a la forma de invocarlo (únicamente a través
de un mensaje) y a su campo de acción, limitado a un objeto y a sus
descendientes, aunque posiblemente no a todos.

Si los métodos son programas, se deduce que podrían tener argumentos, o


parámetros. Puesto que los métodos pueden heredarse de unos objetos a otros,
un objeto puede disponer de un método de dos maneras diferentes:

-Métodos propios. Están incluidos dentro de la cápsula del objeto.

-Métodos heredados. Están definidos en un objeto diferente, antepasado de éste


(padre, "abuelo", etc.). A veces estos métodos se llaman método miembro
porque el objeto los posee por el mero hecho de ser miembro de una clase.

Polimorfismo

Una de las características fundamentales de la POO es el polimorfismo, que


no es otra cosa que la posibilidad de construir varios métodos con el mismo
nombre, pero con relación a la clase a la que pertenece cada uno, con
comportamientos diferentes. Esto conlleva la habilidad de enviar un mismo
mensaje a objetos de clases diferentes. Estos objetos recibirían el mismo mensaje
global pero responderían a él de formas diferentes; por ejemplo, un mensaje "+" a
47

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
un objeto Entero significaría suma, mi
mientras
entras que para un objeto String significaría
concatenación ("pegar" strings uno seguido al otro)

Demonios

Es un tipo especial de métodos, relativamente poco frecuente en los


sistemas de POO,, que se activa automáticamente cuando sucede algo especial.
Es decir, es un programa, como los métodmétodos
os ordinarios, pero se diferencia de
estos porque su ejecución no se activa con un mensaj
mensaje,
e, sino que se desencadena
automáticamente
ticamente cuando ocurre un suceso determinado: la asignación de un valor
a una propiedad de un objeto, la lectura de un valor determinado, etc.

Los demonios, cuando existen, se d


diferencian
iferencian de otros métodos porque
por no
son heredables y porque a veces están ligados a una de las propiedades
propieda de un
objeto, máss que al objeto entero.

A continuación podemos ver un ejemplo de la creación de un objeto a partir de una


clase:

48

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
1.2.1 Instalación y configuración JAVA Eclipse (guía práctica)

¿Qué es JAVA Eclipse?

Al hablar de JAVA Eclipse estamos hablando de una plataforma de


programación en lenguaje JAVA proveniente de la Apache Software Foundation,
Foundation la
cual es 100% gratuita y podremos descargarla fácilmente desde muchos sitios
web de forma rápida y sencilla.

Descarga e instalación

Les propongo
ropongo descargar el pr
programa JAVA Eclipse (Galileo u otra versión)
desde explorador e instalar la misma a través de la guía de instalación que podrán
encontrar en la clase correspondiente a la lectura del presente material.

49

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
1.2.2 Herencia

En la programación orientada a objetos se considera que una clase hereda


de otra cuando la primera es un tipo de la segunda. Una clase es un artefacto
de implementación de tipo que permiten los lenguajes.

Las clases forman jerarquías de herencia y se dice que cuando la clase


Mamífero hereda de la clase Animal, Mamífero es una subclase de Animal y
Animal es una superclase de Mamífero. En general, debemos saber que los
lenguajes sólo permiten heredar de una sola clase aunque hay algunos, como el
lenguaje de programación C++, que tienen herencia múltiple, o sea que una clase
puede heredar de muchas otras.

La subclasificación se parece al subtipado aunque no hay que


confundirse, la subclasificación no fuerza al subtipado. Podríamos tener una
clase que hereda de otra, pero sin compartir entre ellas un concepto de tipo para
crear una jerarquía de tipos. Veamos un ejemplo para que quede más claro:

Supongamos que tenemos la clase que representa a las listas que


responden a los mensajes ¿tamaño?, elemento en la posición X y agregar al final;
y queremos tener la clase Pila (imaginemos una pila de platos), donde sólo se
puede poner arriba y sacar el de arriba. Si quisiéramos implementar dicha clase,
podríamos utilizar la clase lista que ya tenemos y reutilizarla. Si heredamos de
50

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
lista, y hacemos que poner arriba use agregar al final, y sacar el de arriba use
elemento en la posición X más ¿tamaño?, ya tendríamos todo resuelto.

Lamentablemente, el resultado no sería una relación de subtipado entre la


lista y la pila, dado que la pila también sería una lista (podría responder a
elemento en la posición X), cosa que no correspondería con el concepto de pila.
Es claro que una lista y una pila no for
forman
man una relación de tipo, una pila no es una
lista.

En general se considera mala práctica utilizar la subclasificación para


reutilizar implementación sin formar una relación de subtipado.. Generalmente la
técnica que se utiliza para no crear ese tipo de jejerarquías
rarquías mal aplicadas es la
agregación.
51

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Debemos tener en cuenta que se llama agregación cuando un objeto utiliza
a otro. Se dice que un objeto tiene o usa otro.

Veamos otro ejemplo: supongamos que tenemos Rectángulos y Cuadrados,


y queremos que respondan n al mensaje ¿área?. Ambos tipos son muy parecidos,
podríamos decir que un Cuadrado es un Rectángulo con los lados iguales o
también que un Rectángulo es un Cuadrado con los lados desparejos. Podríamos,
entonces, elegir alguna de estas dos jerarquías para reutilizar el comportamiento.
¿Cuál conviene elegir?

Viendo las diferencias entre los objetos, elegir heredar Rectángulo de


Cuadrado parece una opción sencilla, solo hay que agregar un colaborador interno
lado2 y cambiar el comportamiento del mensaje ¿área?. Detengámonos un
momento a pensar, imaginemos que necesitamos un Cuadrado, y que al ser el
Rectángulo subclase de Cuadrado, todo rectángulo es un cuadrado, de esta forma
podríamos usar un rectángulo en su lugar. ¿Suena lógico esto? Claramente no.
Veamos
amos la otra opción, si Cuadrado hereda de Rectángulo, usaríamos sólo un
lado y modificaríamos ¿área?, o podríamos hacer que ambos lados sean iguales y
no tendríamos que modificar nada. Ahora si necesitamos un Rectángulo y
tenemos un Cuadrado, no hay probl
problema,
ema, dado que un cuadrado es un rectángulo
válido. Reutilizamos este conocimiento y la jerarquía estará basada en una
relación de tipos. Recordemos: siempre debemos preocuparnos de hacer que
nuestras jerarquías estén basadas en una relación de tipos.

52

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
En el ejemplo anterior dijimos que un Cuadrado podía ir en lugar de un
Rectángulo. Formalmente quisimos decir que el Cuadrado podía sustituir a un
Rectángulo o, dicho de otra forma, que un Rectángulo es sustituible por un
Cuadrado. La herencia fomenta el polimorfismo, porque generalmente los
lenguajes tienen ciertas reglas que fuerzan a que las subclases puedan sustituir a
las superclases. ¿Qué significa sustituir? Significa que, cuando un objeto que
usamos es sustituido por otro, esperamos que este objeto nuevo nos requiera lo
mismo o menos y que nos dé lo mismo o más que el objeto que sustituyó. De
esta forma nuestras expectativas y nuestras colaboraciones con este objeto no
se verán afectadas.

Herencia simple versus herencia múltiple

Si bien la mayoría de los lenguajes orientados a objetos que se basan en


las clases utilizan herencia simple, hay algunos otros que permiten heredar de
muchas clases al mismo tiempo. El caso más famoso es el lenguaje C++. ¿Por
qué existe la herencia múltiple? La herencia múltiple permite que las clases
pertenezcan a distintas jerarquías adquiriendo el conocimiento, o sea reutilizando
código, de distintas clases. A primera vista nos puede parecer que es una
ventaja contra la herencia simple, pero generalmente pasa que las jerarquías
se deforman, y dejan de estar guiadas por relaciones de tipos para pasar a
estar guiadas por la reutilización de código. De esta forma, en su mayoría
terminan con complejas e inutilizables clases. Además la herencia múltiple plantea
ciertos problemas de implementación que se desencadenan en errores molestos
de corregir. El principal problema es en qué orden se hereda, es decir, qué clase
tiene prioridad sobre otra, lo cual lleva a que algunas clases oculten o
sobrescriban los métodos de otras. Es difícil que el autor de una jerarquía haya
preparado el diseño de esta para actuar junto con otra totalmente dispar, creada
por otra persona. La gente que trabaja con este tipo de lenguajes es muy
cuidadosa a la hora de utilizar la herencia múltiple y en lo posible tratan de
evitarla. Por eso y por algunos otros problemas, la mayoría de los lenguajes opta
por la herencia simple (sumada a otros mecanismos) para la creación de
jerarquías de tipos.

53

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
¿Por qué objetos?

Cuando nos encontramos frente a un problema o una situación que


queremos entender, para luego resolver, creamos en nuestra mente un modelo
que lo representa. Un modelo no refleja totalmente la problemática. Nosotros
mismos, al crear el modelo, elegimos enfocarnos en algunas características y
dejamos otras de lado. Luego, operamos sobre este y contraponemos los
resultados con el problema real. Es necesario tener en cuenta que, en base a las
conclusiones que nos encargamos de obtener, volvemos al modelo y lo ajustamos
para lograr mejores resultados la próxima vez.

El paradigma de objetos es un filtro que se encuentra entre el problema y el


modelo, que polariza el entendimiento de la situación acomodándolo a sus
conceptos. Afortunadamente, el paradigma de la orientación a objetos permite que
la interpretación entre la realidad, la problemática y el modelo sea muy fácil. Un
objeto es tangible y es fácilmente relacionado a un elemento del dominio del
problema, la carga mental que implica el pasaje del modelo al problema es
imperceptible.

Esta es la gran ventaja frente a otros paradigmas de programación, dado


que permite interpretar fácilmente la problemática. Además la comunicación entre
individuos que se manejen tanto en el modelo (programadores) como en la
situación de interés (clientes) es sencilla, ya que se maneja el mismo idioma en
ambos mundos. Se dice que entre el modelo y el problema debe existir una
relación de isomorfismo. Un isomorfismo es una relación entre dos elementos
cuando ambos son indistinguibles, ambos cumplen las mismas propiedades y
todo lo que es cierto para uno lo es para el otro, del mismo modo todo lo que es
54

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
falso para uno lo es para el otro. Se dice que ambos elementos son isomorfos
entre sí. Por ejemplo, si estamos en el ámbito bancario, tendremos un objeto
Cuenta que representa una cuenta real en el banco. Entonces cuando el cliente
diga la palabra “cuenta” nosotros entenderemos que se trata de un objeto de este
tipo en forma inmediata. Y viceversa, cuando nosotros hablemos de una Cuenta,
el cliente comprenderá, sin ningún inconveniente, que queremos decirle algo sobre
una de ellas.

De este ejemplo podemos sacar algunas conclusiones; no puede haber un


elemento del modelo que represente a más de un concepto del dominio por
modelar. Tampoco lo opuesto, que un concepto del problema esté representado
por más de un elemento del modelo.

55

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
1.2.3 Arreglos (teoría y práctica)

El trato que reciben los arreglos (array) es especial dentro de la POO,


POO ya
que son objetos manejados por la máquina virtual y el lenguaje. Para acceder a
los arreglos usando la reflexión debemos tener algunas consideraciones. Para
discriminar entre las clases comunes y los array utilizamos el método isArray()
provisto en Class.. Las clases de los array tienen nombres particulares. Primero,
tienen tantos caracteres
cteres de este tipo [ como dimensiones tiene el array. Luego,
dependiendo del tipo de dato del array, utiliza una codificación distinta.
distint Finaliza
con este carácter ;

Ejemplo:

String [] unArray = new String[4]; // un array con 4 posiciones vacías


String [] otroArray = new String [] {“a”, “b”} //
// creamos una array
String [][] array = new String [][] {};
// verificamos que la clase es un array
assertTrue(array.getClass().isArray());
// verificamos el nombre
assertEquals(

56

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
array.getClass().getName(),
“[[Ljava.lang.String;”);

Debemos saber que también contamos con una clase auxiliar llamada
Array la cual se encarga de brindar una gran ayuda para trabajar con array y
reflexión. Por ejemplo podemos acceder a creación de nuevos array utilizando el
método denominado newInstance. Este método espera el tipo de los elementos y
las dimensiones.

// creamos un array
String [] a = (String[])
Array.newInstance(String.class, 3);
// verificamos la longitud
assertEquals(3, a.length);
// verificamos que estén en null los elementos
assertArrayEquals(
new String [] {null, null, null}, a);

Además, Array ofrece métodos para leer y escribir valores en los array, así
como también obtener su la longitud. Los métodos para acceder a los elementos
están discriminados por tipos primitivos y luego por uno general para objetos.

assertEquals(Array.getLength(new int [] {4, 3}), 2);


assertEquals(
Array.getLong(new long [] { 2L }, 1),
2
);

57

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Enumeraciones para los Arrays

Las enumeraciones son clases que definen ciertos atributos estáticos donde
cada referencia es una instancia de la misma clase (o una subclase anónima). Por
lo tanto, podemos utilizar las mismas herramientas que vimos para inspeccionar y
manipular clases y atributos mediante reflexión. Además existe cierto protocolo
específico para cuando se da el caso de las enumeraciones.

Empezaremos viendo cómo determinamos que una clase es en realidad


una enumeración. Para ello usamos el método isEnum perteneciente a Class, de
la siguiente forma:

// declaramos una enumeración


enum TEST {

A, B, C, D, E
}
// verificamos que la clase está marcada como tal
assertTrue(TEST.class.isEnum());

Cuando queríamos saber todos los elementos de una enumeración


utilizábamos el mensaje values(). Ahora, para obtener el mismo resultado en el
código que utilizamos, le enviamos el mensaje getEnumConstants() a la clase de
la enumeración. Este método nos devuelve un array con los distintos elementos.

assertArrayEquals(
TEST.values(), TEST.class.getEnumConstants());

58

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
1.2.4 Poliformismo

Al escuchar la palabra polimorfismo lo primero que se nos viene a la


mente es "Muchas Formas" y bueno, si, básicamente esta es la idea general, pero
y que mas gira en torno a esto?

Ahora veremos algunos ejemplos y puntos a tener en cuenta sobre el


polimorfismo en la programación orientada a objetos y para eso aplicaremos
otros conceptos trabajados con anterioridad..... y en las clases desarrollaremos
ejemplos en Java donde pondremos a prueba lo aprendido en esta entrada.

Algunas Ideas

Tal como se mencionó en el presente módulo, Poliformismo podemos


definirlo como la capacidad que tienen los objetos de comportarse de múltiples
formas, programando de manera general en vez de hacerlo de forma específica.

Alguna vez consultando, definían este concepto como la forma en la que


podemos tratar una subClase como si fuera una Clase del tipo de su superClase,
usando solo los métodos o atributos disponibles para la Clase declarada..... Es
decir, si tenemos una clase "X" podemos decir que "X" es de tipo "Y" esto se
cumple solo si existe una relación de herencia entre ellas, ya sea si "X" hereda de
"Y" (extends) o si "X" implementa a "Y" (implements).

Retomando (de manera reducida) el ejemplo, se explica mejor lo anterior


usando "X" como cualquier clase Cuadrado, Triangulo o Circulo y "Y" como la
clase FiguraGeometrica, por lo tanto decimos que por ejemplo la clase Triangulo
es de tipo FiguraGeometrica, en Java esto lo representamos así:

class FiguraGeometrica{
}
class Triangulo extends FiguraGeometrica {
}

59

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
public class Principal{
public void metodo(){
/**Puedo crear objetos polimorficos*/
/**Objeto Triangulo de tipo FiguraGeometrica*/
FiguraGeometrica triangulo=new Triangulo();
}
}

Vemos que FiguraGeometrica es la superClase y Triangulo es la clase


hija o subClase, y por medio del polimorfismo podemos crear una instancia de
Triangulo de tipo FiguraGeometrica.

Algunas Consideraciones

Como en todo, tenemos unas reglas que se deben cumplir y tener en


cuenta cuando vamos a trabajar con objetos polimórficos, estas son :

• Una variable de referencia puede ser de un solo tipo, y una vez que fue
declarada, ese tipo jamás puede modificarse..... por ejemplo, si declaramos
triangulo de tipo FiguraGeometrica, no podemos decir mas adelante que
el mismo objeto triangulo es de tipo FiguraPuntiaguda...

• Una referencia es una variable, de manera que puede ser reasignada a


otros objetos (a menos que se declare como final). por ejemplo podemos
hacer lo siguiente:

FiguraGeometrica miFiguraGeometrica = new FiguraGeometrica();


Cuadrado miCuadro=new Cuadrado();
/**Puedo crear objetos polimorficos, asignando su referencia*/
miFiguraGeometrica=miCuadro;

• Una variable de referencia puede tomar como referencia cualquier objeto


del mismo tipo, o un subtipo del mismo..... va muy ligada a la anterior, pero
nos dice que si por ejemplo tenemos la clase cuadroPequeño que es
60

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
subClase de cuadro, al ser "nieta" de FiguraGeometrica, si se crean
instancias de ella, se pueden reasignar a instancias de
FiguraGeometrica...

• Un tipo de variable de referencia determina los métodos que pueden ser


invocados sobre el objeto que la variable referencia.... Triangulo al ser de
tipo FiguraGeometrica puede acceder no solo a los métodos de la clase
Triangulo sino también a los de FiguraGeometrica (tiene que existir una
relación de Herencia entre ellos)

• Una variable de referencia puede tener como tipo el de una interface. Si es


declarada de esta manera, podrá contener cualquier clase que implemente
la interfaz..... las interfaces también permiten el uso de herencia, por lo
tanto podemos crear objetos usando para esto una interfaz, por ejemplo si
FiguraGeometrica fuera una interface, lo anterior seria igual..... (esto
también aplica para las clases Abstractas).

Las clases abstractas y las interfaces (al ser clases completamente


abstractas) no pueden ser instanciadas, o no directamente, la única forma de
hacerlo es mediante la herencia, ya que así extendemos sus funcionalidades
creando objetos referenciando clases pero siendo del tipo de su superClase
(abstracta o interface).

1.2.5 Encapsulamiento

¿Qué es encapsulamiento?

El encapsulamiento es la única técnica de poder ocultar datos / información


del alcance del usuario en forma directa. O sea, que es posible acceder a dicha
información pero exclusivamente a través de un llamado.

61

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Definición de Wikipedia

En programación modular
modular, y más específicamente en programación
orientada a objetos,, se denomina Encapsulamiento al ocultamiento del estado,
es decir, de los datos miembro de un objeto de manera que sólo se pueda cambiar
mediante las operaciones definidas para ese objeto.

Cada objeto está aislado del exterior, es un módulo natural, y la aplicación


entera se reduce a un agregado o rompecabezas de objetos. El aislamiento
protege a los datos asociados de un objeto contra su modificación por quien no
tenga derecho a acceder a ellos, elimi
eliminando
nando efectos secundarios e interacciones.

De esta forma, el usuario de la clase puede obviar la implementación de los


métodos y propiedades para concentrarse sólo en cómo usarlos. Por otro lado,
lado se
evita que el usuario pueda cambiar su estado de maneras imprevistas e
incontroladas.

Como se puede observar en el diagrama, las variables del objeto se


localizan en el núcleo del objeto. Los métodos rodean y esconden el núcleo del
objeto de otros objetos en el programa. Al empaquetamiento de las variables de
un objeto con la protección de sus métodos se le llama encapsulamiento.
Típicamente,, el encapsulamiento es utilizado para esconder detalles de la puesta
en práctica no importantes de otros objetos. Entonces, los detalles de la puesta en

62

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
práctica pueden cambiar en cualquier tiempo sin afectar otras partes del
programa. Dentro de las formas de encapsular podemos encontrar:

1. Estándar: (Predeterminado)
2. Abierto: Hace que el miembro de la clase pueda ser accedido desde el
exterior de la Clase y cualquier parte del programa.
3. Protegido: Solo es accesible desde la Clase y las clases que heredan (a
cualquier nivel).
4. Semi cerrado: Solo es accesible desde la clase heredada.
5. Cerrado: Solo es accesible desde la Clase.

Public Class MiClase {


Private int tipo;
Public void setTipo (int t) }
Tipo = t;
}
Public int getTipo () {
Return tipo;
}
}
Class AccesoIndirecto {

Public static void main (string[] args) {

MiClase mc = new MiClase();

mc.setTipo(5);

System.out.println(“El tipo es: “ + ms.getTipo());

63

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
1.3.1 Proyectos (teoría y práctica)

Procesos de Desarrollo de Software

Evidentemente, el desarrollo de un sistema software debe seguir un


proceso que especifique cómo debe ser, que permita controlar y seguir la
evolución del sistema y que permita establecer aproximadamente su coste. El
estudio de las características de estos procesos se lleva a cabo en el ámbito de la
comunidad de Ingeniería del Software. Básicamente, podemos hablar de dos tipos
procesos a la hora de implementarlo como desarrollo:

• En cascada.
• Iterativo (o incremental).

La diferencia fundamental entre ellos consiste en la forma de dividir un


proyecto en partes más pequeñas.

Los procesos en cascada dividen un proyecto según las actividades. La


construcción de un sistema software conlleva una serie de actividades que
componen el ciclo de vida software: análisis de requisitos, diseño, implementación
y pruebas.

De esta manera, los procesos en cascada dividirán un proyecto de un año


de duración en, por ejemplo, una fase de análisis de dos meses, una fase de
diseño de cuatro meses, una fase de implementación de tres meses y una de
prueba de tres meses.

Por su parte, los procesos iterativos dividen un proyecto en subconjuntos


de funcionalidad. De esta forma, un proyecto de un año se dividiría en tres
iteraciones de cuatro meses. En la primera iteración, se realizaría todo el ciclo de
vida software para la cuarta parte de los requisitos. El resultado de la primera
iteración sería un sistema software con la cuarta parte de la funcionalidad. En las
siguientes iteraciones se continuaría evolucionando ese sistema, introduciendo el
resto de funcionalidad.

64

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Dentro de la comunidad orientada a objetos, se suele optar por procesos
iterativos que responden mejor al problema derivado de los cambios en los
requisitos. En muchos campos de aplicación, los requisitos van cambiando a lo
largo del desarrollo del sistema. Por lo tanto, los procesos en cascada se
muestran menos efectivos; ya que, su flexibilidad ante estos cambios es mucho
menor.

Lenguaje UML:

¿Qué es UML? ¿Por qué se lo considera un lenguaje?

Para poder seguir avanzando y si bien no está dentro de nuestros temas


foco, considero que es importante poder tener presente el concepto de UML junto
con algunas aclaraciones al respecto para poder comprender y avanzar sobre los
temas que siguen en las siguientes clases.

UML es ante todo un lenguaje. Es así dado que un lenguaje proporciona un


vocabulario y una serie de reglas para permitir una comunicación. En este caso,
este lenguaje se centra en la representación gráfica de un sistema. Este lenguaje
nos indica cómo crear y leer los mo-delos, pero no dice cómo crearlos. Esto último
es el objetivo de las metodologías de desarrollo.

Los objetivos de UML son muchos, pero se pueden sintetizar sus funciones:

• Visualizar: UML permite expresar de una forma gráfica un sistema de forma


tal que otro lo puede entender.
• Especificar: UML permite especificar cuáles son las características de un
sistema antes de su construcción.
• Construir: A partir de los modelos especificados se pueden construir los
sistemas diseñados.
• Documentar: Los propios elementos gráficos sirven como documentación
del sistema desarrollado que pueden servir para su futura revisión.

65

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Aunque UML está pensado para modelar sistemas complejos con gran
cantidad de software, el lenguaje es los suficientemente expresivo como para
modelar sistemas que no son informáticos, como flujos de trabajo (workflow ) en
una empresa, diseño de la estructura de una organización y por supuesto, en el
diseño de hardware.

Un modelo UML está compuesto por tres clases de bloques de


construcción:

• Elementos: Los elementos son abstracciones de cosas reales o ficticias


(objetos, acciones, etc.).
• Relaciones: relacionan los elementos entre sí.
• Diagramas: Son colecciones de elementos con sus relaciones.

(Ejemplo gráfico de un bloque en UML)

66

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Origen de los patrones de diseño

Los patrones surgen al realizar un esfuerzo mental (modelos mentales


durante el desarrollo de nuestra mente en el momento en que estamos pensando
cómo resolver la necesidad) para generalizar la solución a problemas diversos y
aparentemente independientes. Por lo tanto, cualquiera puede encontrar y utilizar
sus propios patrones de diseño a través de la experiencia. Además, los patrones
son un buen vehículo para transmitir dicha experiencia a otras personas. Veamos
un ejemplo:

Supongamos que hemos terminado una aplicación de generación de


facturas. Una parte de nuestro diseño contiene el siguiente diagrama de clases:

En otra ocasión diseñamos una aplicación de gestión de un almacén de


repuestos, donde nos encontramos con este diagrama de clases en una parte del
diseño:

67

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Se trata de dos estructuras muy similares, pero no es esto lo que nos
sugiere la existencia de un patrón. Sino el papel que juegan estas estructuras en
el diseño. Y, en efecto, dicho papel se repite en ambos casos:

• Factura es algo que se compone de varias Líneas de factura, y además,


las líneas de factura no tienen sentido sin la existencia de la Factura.
• Almacén es algo que se compone de Repuestos, y además, los repuestos
requieren la existencia de un Almacén.

Hemos demostrado un patrón de diseño; Se trata de una idea: un objeto


que almacena otros objetos, y éstos últimos no tienen sentido sin su "almacén". Se
trata del patrón "Continente-Contenido":

Pero no es el único patrón que podemos encontrar:

• Línea de Factura es un objeto que se compone necesariamente de


Concepto, Cantidad y Precio.
• Repuesto es un objeto que se compone necesariamente de Pieza,
Garantía y Precio.

Aquí hay otra idea que se puede generalizar: un objeto que se desglosa en
otros objetos. Podríamos llamarlo el patrón "Objeto - Componente":

68

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Cuando nos enfrentamos a un nuevo problema intentaremos aplicar
los patrones que conozcamos, y esto no es una sugerencia, sino el
comportamiento natural de todo ser humano. Por otra parte, es muy importante
tener en cuenta que los patrones no sólo surgen y se aplican a diseños diferentes.
Un mismo patrón puede aplicarse varias veces en un mismo diseño.

Presentación de diversos Patrones de Diseño en el mundo POO:

1 - El Patrón proxy

Este patrón consiste en interponer un intermediario (Proxy) entre un objeto


y los demás que lo utilizan. Se diferencia del patrón Adaptador en que el objeto
"adaptado" solamente puede ser manipulado a través del objeto Proxy.

Se suele utilizar para implementar comportamientos "vagos" (lazy). Por


ejemplo, si tenemos muchos objetos imagen en un documento, se tardaría mucho
tiempo en abrir el documento al cargar las imágenes de disco. Para evitarlo
podemos sustituir los objetos imagen por objetos proxyImagen, con la misma
interfaz, pero que solamente cargan la imagen cuando se va a visualizar.

69

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Debemos insistir en dos aspectos que caracterizan el patrón Proxy:

• El objeto Apoderado tiene el mismo interfaz que el objeto "Protegido". Para


facilitar esto se puede derivar el objeto Apoderado de la misma clase
padre que el objeto "Protegido", pero no es absolutamente necesario.
• El objeto "Protegido" solamente puede ser manipulado por su
correspondiente Apoderado.

Un ejemplo típico de aplicación del patrón proxy es el de un editor de


documentos. El editor podrá incluir imágenes y dibujos complejos, y se plantea el
problema de recuperar todos estos costosos objetos cada vez que se abre el
documento. La aplicación del patrón proxy soluciona el problema definiendo un
"representante", que ocupe su lugar, hasta que sea necesario cargarlos.

70

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
2 - El Patrón Bridge (Puente)

Tal como sabemos, una abstracción puede tener diferentes


implementaciones. El mecanismo de herencia permite que la implementación de
una abstracción evolucione sin modificar significativamente el diseño. Esto es
cierto mientras la abstracción en sí misma (básicamente, su interfaz) no
evolucione. Es decir, no se puede modificar independientemente una
implementación y la abstracción a la que está ligada. Este patrón consigue que
esto sea posible.

La parte importante del esquema son las clases Abstracción y


ClaseObjetoImplementor. Los descendientes de Abstracción son "evoluciones"
de la abstracción que pueden o no mantener la implementación. Al mismo tiempo,
los descendientes de ClaseObjetoImplementador son "evoluciones" de la
implementación independientes de la evolución de Abstracción.

El esquema estático es el siguiente:

71

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
3 - El Patrón Iterador (Iterator)

Este patrón se utiliza en relación a objetos que almacenan colecciones de


otros objetos, por ejemplo, las listas. El uso de un objeto Iterador permite recorrer
los elementos del agregado independientemente de su organización. Si todos los
objetos agregado (listas, árboles, etc.) generan un objeto Iterador con la misma
interfaz resulta muy fácil operar con ellos y se facilitan los cambios de
implementación.

El objeto agregado puede crear objetos Iterador para la implementación


concreta de dicho agregado. Diferentes implementaciones, diferentes iteradores. A
partir de entonces, un objeto cliente puede manipular el agregado únicamente a
través del iterador. Si cambiamos la implementación del agregado (por ejemplo, la
lista pasa a ser un árbol), el objeto cliente no resulta afectado. Se trata de un
patrón muy común y ampliamente utilizado. En el caso de las listas, podríamos

72

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
recorrerla sin exponer su estructura interna, permitiendo así diferentes tipos de
listas (listas normales, con vectores, etc.) y diferentes tipos de iteradores:

1.3.2 Importación de librerías (teoría y práctica)

Tal como sabemos, dentro de absolutamente todas las plataformas de


programación existes librerías predefinidas. Qué significa esto? Que los
desarrolladores de dicha plataforma (en nuestro caso Eclipse) ya dejado
herramientas ya elaboradas a fin de que sea más sencillo para nosotros los
programadores poder realizar ciertas tareas. Dichas herramientas se consideran
tales como librerías y en todos los casos sólo hay que conocerlas para así
simplemente poder importarlas y utilizarlas.

Cuando instalamos Java en nuestro ordenador instalamos múltiples


herramientas, entre ellas podemos distinguir una serie de “librerías” (paquetes) a
cuyo conjunto solemos referirnos como “biblioteca estándar de Java”. Las librerías
contienen código Java listo para ser usado por nosotros. Ese es el motivo de que
podamos usar clases como System o String sin necesidad de programarlas.

73

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
¿Dónde se encuentra el código de estas librerías? En los archivos que se
instalan en nuestro ordenador cuando instalamos Java.

(gráfico descriptivo del contenido de aplicaciones que se descarga al momento de


instalas JAVA Eclipse)

¿Podemos acceder al código de estas librerías? La respuesta es que no. La


biblioteca estándar de Java se facilita como código cerrado, es decir, como código
máquina.
áquina. No podemos acceder al código fuente. Esto tiene su lógica porque si
cada persona accediera al código fuente de los elementos esenciales de Java y
los modificara, no habría compatibilidad ni homogeneidad en la forma de escribir
programas Java.

¿Para qué nos sirve la biblioteca si no podemos acceder a su código


fuente? Aunque no podamos acceder al código fuente, sí podemos crear objetos
de los tipos definidos en la librería e invocar sus métodos. Para ello lo único que
hemos de hacer es conocer
onocer llas clases y la codificación de los métodos, y esto lo
tenemos disponible en la documentación de Java accesible para todos los
programadores a través de internet o cds de libros y revistas especializadas.

74

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
¿Cómo se invoca / carga una librería? Muy sencillo
sencillo,, siguiendo los pasos
que se muestran en las siguientes líneas.

1 - Expande la carpeta “lib”” dentro de Eclipse y selecciona todos los archivos JAR
que necesitas.

75

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
2 - Haz clic derecho en los archivos JAR y dirígete a Construcción de ruta (Build
(
Path).

3 - Selecciona Agregar a construcción de ruta ((Add to Build Path). Los archivos


JAR desaparecerán de lib y reaparecerán en Bibliotecas de referencia
(Referenced Libraries).

Ejemplo de invocación:

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
76

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Trabajando con Paquetes

Los paquetes son la manera en que tiene Java para organizar las clases en
agrupaciones que tengan sentido. Los paquetes sirven para importar las clases
que usamos. También para permitir qué clases, que representan cosas distintas
pero se llaman igual, pueden coexistir (por ejemplo la clase Punto, para geometría
y la clase Punto para gráficos 3D). Los paquetes en Java siguen la misma
estructura de directorios que contiene a los archivos fuentes. Para crear un
paquete, tan solo debemos crear una clase que indique que pertenece a ese
paquete, y respetar la estructura de directorios. Para ello utilizamos la palabra
clave package seguida del nombre completo del paquete (paquetes padres y su
nombre al final). Debe ser la primera instrucción del archivo fuente:

package padre1.padre2.padre3.nombre;

En el ejemplo deberíamos tener la estructura de directorios


correspondientes a padre1, dentro de este un directorio padre2, dentro, otro
llamado padre3 y, finalmente, dentro de este último el directorio nombre con el
archivo fuente de la clase en él.

Para importar todas las clases de un paquete debemos declararlo utilizando


import y el nombre completo del paquete, e indicando con un asterisco (*) que
importamos todas la clases que están en el nivel indicado (no se importan las
clases que estén en subpaquetes).

import red.user.java.*;

import red.user.java.ClaseParticular;

Las instrucciones de import deben ir después de la declaración de paquete


y antes de la definición de la clase. Finalmente podemos importar todos los
métodos estáticos de una clase si agregamos el modificador static a la instrucción
import de una clase.

77

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
import static red.user.java.ClaseConMetodosEstaticos;

Nosotros hemos utilizado este tipo de importación en los unit test.

1.3.3 Almacenamiento en archivos (teoría y práctica)

Por lo general, en la medida en que sólo deseemos realizar algoritmos que


procesen cierto tipo de información (ingresada o pre escrita), y que entreguen un
resultado en función de los procesos realizados internamente, el desarrollo de un
algoritmo será relativamente sencillo; no más de lo que uno mismo pueda llegar a
complejizarlo.

Ahora bien, en el momento en el que necesitemos leer, modificar y/o


almacenar información; comenzaremos el camino hacia el uso de librerías
específicas para poder hacer uso de documentos externos.

Es en función de esto que les propongo una serie de ejemplos en dónde


podrán encontrar diversos usos del Java IO (Input / Output).

Ejemplo de FileWriter y FileReader

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class C1 {
public static void main(String args[]) throws IOException {
File file = new File("Fich1.txt");
file.createNewFile(); // crea el fichero
FileWriter writer = new FileWriter(file);
writer.write("Game\n Thrones\n");

78

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
writer.flush();
writer.close();
FileReader fr = new FileReader(file);
char[] a = new char[50];
fr.read(a); // lee el contenido del array
for (char c : a)
System.out.print(c);
fr.close();
}
}

BufferedReader y BufferedWriter

Sin buffer cada petición de lectura o escritura es manejada directamente por


el sistema operativo subyacente. Esto se llama unbuffered I/O. Con buffered se
pueden leer y escribir largas cantidades de caracteres y guardarlas en una zona
de memoria llamada búfer en lugar de acceder al disco duro, etc. con lo que
optimizamos recursos. Son de mayor nivel que FileReader y FileWriter.

Definición de las clases:

public class BufferedReader extends Reader


public class BufferedWriter extends Writer

Algunos métodos de BufferedReader y BufferedWrite:

BufferedReader
public String readLine() throws IOException
// Recupera una linea del fichero.
public int read() throws IOException
public boolean ready() throws IOException
public void reset() throws IOException
public long skip(long n) throws IOException

79

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
BufferedWriter
public void flush() throws IOException
// Escribe en el fichero lo que está en la memoria buffer.
public void close() throws IOException
// Libera recursos del s.o.
public void write(int c) throws IOException
public void newLine() throws IOException

Ejemplo de uso de BufferedReader y BufferedWriter

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class C1 {
public static void main(String[] args) throws IOException {
File fichero = new File(fich1.txt");
// FileWriter crea el fichero
FileWriter fw = new FileWriter(fichero);
FileReader fr = new FileReader(fichero);
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw = new BufferedWriter(fw);
bw.write("Person of interest");
bw.close();
String s;
// Lee una linea del fichero.
// Si no hay datos devuelve null.
while ((s = br.readLine()) != null) {
System.out.println(s);
// Person of interest
}

80

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
fr.close();
}
}

PrintWriter

Clase mejorada desde Java 5. Puede escribir una línea entera en un


fichero. El constructor creará el fichero si no existe.

public class PrintWriter extends Writer

Los constructores con parámetros File o String lanzan una


FileNotFoundException. Algunos métodos de PrintWriter (no lanzan
Exceptions):

void flush()
// Escribe en el fichero lo que está en la memoria buffer.
PrintWriter format(String format, Object... args)
PrintWriter printf(String format, Object... args)
void write(String s)
PrintWriter append(char c)
void print(String s)
void println(Object x)
void close()

Ejemplo de uso PrintWriter:

public static void main(String[] args) throws IOException {


FileWriter fichero = null;

81

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
PrintWriter pw = null;
fichero = new FileWriter("fich8.txt");
pw = new PrintWriter(fichero);
for (int i = 0; i < 2; i++)
pw.println("Linea " + i);
//Escribe en el fichero:
//Linea 0
//Linea 1
pw.close();

}
}

File

No se usa para leer ni escribir datos si no para crear ficheros, abrirlos, tratar
con paths, etc. Oracle lo define como representación abstracta de nombres de
ficheros y directorios.

public class File extends Object implements Serializable, Comparable<File>

Algunos métodos de File:

public boolean createNewFile() throws IOException


// Crea el fichero si no existe y si existe devuelve false.

public boolean delete()


// Borra un fichero o un directorio si estamos en un directorio y está vacio.
public boolean isFile() y public boolean exists()

82

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
// Preguntan si existe el fichero. Exists también comprueba directorios.
public String[] list()
public String[] list(FilenameFilter filter)
// Devuelve un array de strings con los nombres de los ficheros y directorios que
encuentra en el directorio especificado por el "abstract pathname."
public boolean mkdir()
// Si el directorio no existe tienes que crearlo explícitamente.
public boolean renameTo(File dest)
// Renombrar un fichero o un directorio
public static final String separator
// Pone la barra de separación del path en función del sistema actual.
public boolean isDirectory()

Ejemplo de uso de File:

import java.io.File;
import java.io.IOException;

public class C1 {
public static void main(String[] args) throws IOException {
File myDir = new File("myDir");
// No crea el directorio mydir.
System.out.println("Creando directorio: " + myDir.mkdir()); // true
System.out.println("Elementos dentro del directorio: " + myDir.list().length); //0
File f = new File(myDir, "fich1.txt");
if (!f.exists()) {
System.out.println("Create file f: " + f.createNewFile()); // true
}
System.out.println("Eliminar fichero f: " + f.delete());
// true
System.out.println("Eliminar directorio mydir: " + myDir.delete());
// true
File newDir = new File("newDir");

83

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
System.out.println("Rename mydir: " + myDir.renameTo(newDir));
// false
File newf = new File("fich2.txt");
System.out.println("Rename file:" + f.renameTo(newf));
// false
}
}

1.3.4 Diagnóstico y excepciones (teoría y práctica)

¿A qué nos referimos con diagnóstico y excepciones? Tal como nos infiere
la mente al escuchar la palabra y llevándonos hacia el resultado de un estudio
médico sobre nuestro cuerpo, sí diríamos que no estamos errados. Se trata del
diagnóstico que debemos hacer durante el proceso de planeamiento de un
proyecto, en el desarrollo, al finalizarlo y también durante su vida útil; Logrando
que podamos detectar errores dentro de los tres procesos de funcionamiento
(durante el ingreso, procesamiento y egreso de los parámetros / información).

Cuando nuestro programa está siendo ejecutado y ocurre alguna situación


inesperada, el sistema notifica de este hecho mediante eventos denominados
excepciones. Las excepciones son la forma de avisar y detectar errores en la
ejecución o cuando ocurre un acontecimiento extraño. En Java las excepciones
son objetos y podemos definir nuestra propia jerarquía de excepciones. Aquí las
analizaremos.
Es necesario tener en cuenta que una excepción es un evento no
esperado que ocurre durante la ejecución de un programa y que interrumpe el
flujo normal de éste. Cuando ocurre un error durante la ejecución de un método,
éste crea un objeto con información sobre las causas del error en el contexto de la
ejecución. Este es el objeto excepción y es pasado al sistema (a la máquina
virtual) para que lo trate. Esto se conoce como lanzar una excepción. Cuando
lanzamos una excepción el sistema trata de encontrar algún método en la cadena
de llamados que puede manejarla. Para entender cómo funciona esto, en primer

84

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
lugar tenemos que comprender cómo funcionan las llamadas a métodos, por lo
tanto lo analizaremos a continuación.

Cuando el sistema ejecuta un método asociado a un envío de mensaje (o


un método estático), crea una estructura en la memoria con la información
relacionada, el método, los argumentos, entre otros datos. Estas estructuras,
llamadas activation records o registros de activación, se van enlazando a
medida que de un método llama a otro.

De esta forma cuando un método finaliza su ejecución, se continúa con la


ejecución del método anterior en la cadena. A esta cadena se la conoce como call
stack (pila de llamadas) y viene de la representación en la memoria de los
activation records. Cuando lanzamos una excepción, el runtime (la máquina
virtual Java) va buscando en el call stack, en orden reverso de ejecución, si en
alguno de los métodos hay un exception handler, o manejador de excepciones,
asociado al tipo de la excepción lanzada.

85

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Recordemos que cuando encuentra el primer handler, se encarga de
ejecutar el código asociado y posteriormente regresa la ejecución al método al
cual pertenece el handler correspondiente, de esta forma se encarga de abortar la
ejecución de los métodos del call stack que están entre el punto de error y el
handler.

86

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Cuando el sistema no encuentra ningún handler apropiado, ejecuta su
propio handler existente por defecto, que aborta la ejecución del programa. El
hecho de encontrar un manejador apropiado y de ejecutarlo se conoce como
catchear (de catch) o atrapar la excepción. En Java los objetos que pueden ser
lanzados como excepciones son aquellos que son del tipo Throwable o de una de
sus subclases. Esta clase tiene dos subclases que definen la estructura básica de
todas las excepciones y errores en Java. Por un lado, tenemos los errores graves
de sistema, que no deberían ser nunca de interés a una aplicación, representados
por la clase Error y sus descendientes. Por otro, las situaciones excepcionales
durante la ejecución de una aplicación, representados por la clase Exception y
sus subclases. Es de particular interés la subclase RuntimeException, que
generalmente representa errores en la lógica del programa que tienen un trato
especial en el lenguaje.

87

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Try / Catch / Finally

Los avances en Java han dado como resultado el desarrollo del


lanzamiento de errores durante el ciclo de operación principalmente en
anidamientos. En Wikipedia podremos encontrar la siguiente definición:

“El código es ejecutado normalmente hasta que ocurre una excepción, en


este caso "salta" al manejo de errores adecuado; es decir las sentencias pueden o
no ejecutarse, en función de si previamente se haya lanzado un error o no. En
algunos casos puede darse que exista código que debe ejecutarse al final,
independientemente de si se haya lanzado o no un error (en nuestro caso podría
ser la operación de cerrar el archivo para que otros puedan acceder a él), para lo
cual también hay sentencias especiales.”

Si bien es un problema que este anidamiento puede llegar a ser muy


grande, la principal razón para utilizar el lanzamiento de errores es que con el tipo
de estructura anterior se pierde la noción del camino principal, y cuesta mucho
más encontrar las sentencias de ejecución normal, (en este caso Cuerpo), por la
presencia de las condiciones de error que entorpecen la legibilidad.

Algunos lenguajes como Java han tenido esto en cuenta y desarrollaron el


lanzamiento de errores, que consiste en separar el tratamiento de errores al final
de la instrucción, para no perder de vista el hilo de continuidad. Para esto, los
métodos en lugar de devolver un valor lógico (verdadero o falso) para determinar
si la operación se efectuó correctamente, deben "lanzar" excepciones.

INTENTAR
LeerArchivo (f)
AvanzarArchivo (f)
ObtenerEntero (Leer(f))
Cuerpo

CAPTURAR Error1 (ExcepciónDeAperturaDeArchivo)


Imprimir "No se pudo abrir el archivo"

88

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
CAPTURAR Error2 (ExcepciónDeLecturaDeArchivo)
Imprimir "Se llegó al final del archivo"

CAPTURAR Error3 (ExcepciónDeConversiónDeDatos)


Imprimir "El valor no es entero)

FINALMENTE
CuCerrarArchivo (f)

Esta estructura está


generalmente asociada al manejo
de excepciones, aunque puede
ser usada para otros fines. El
objetivo es que se ejecuta el
código del bloque seguido a try y
pueden pasar dos cosas, que el
código se ejecute exitosamente o
que ocurra una excepción.
Debemos tener en cuenta
que si nos encargamos de
especificar que se realice la
acción de atrapar una excepción
con la etiqueta catch, entonces se
procederá a ejecuta el código
asociado a esta. Si finalizó la
ejecución en forma correcta o se terminó de ejecutar el código que corresponde a
catch, y tuvimos cuidado de especificar código con la etiqueta finally, se evalúa lo
que corresponde. Veremos esta estructura en más detalle más adelante, en la
sección de excepciones.

89

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
try {

throw new Exception (“ocurrió un error”); // continúa en B

// si finaliza bien continúa en A
} catch (Exception e) {

// B, continúa en A
}

// A

try {

throw new Exception (“ocurrio un error”); // continúa en B

// si finaliza bien continúa en B
} finally {

// B, continúa en A si término bien
}

// A

try {
throw new Exception (“ocurrio un error”); // continúa en B

// si finaliza bien continúa en C
} catch (Exception e) {
// B, continúa en C

90

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
} finally {

// C, continúa en A si término bien
}

// A

Las excepciones son bastante sencillas de utilizar. Empecemos por ver


cómo lanzamos una excepción.

throw new IllegalArgumentException(“unParametro”);

Como vemos, nos encargamos de utilizar la palabra clave throw seguida


del objeto excepción que queremos lanzar. Generalmente este es creado en ese
mismo momento, como en el ejemplo. Cuando estamos interesados en manejar
excepciones, tenemos que envolver el código que la puede provocar con la
declaración try y catch.

try {
… // código que en algún punto puede producir una excepción
} catch (TipoDeExcepcion excepcion) {
… // código para manejar la situación de error
}

El código dentro del catch (handler) se ejecuta cuando el runtime decide


que es el handler apropiado para tratar la excepción. Solamente pueden tratar

91

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
excepciones que sean del tipo (o un subtipo) del especificado y dentro del bloque
en que se tiene acceso al objeto excepción, tal como si fuera un parámetro. Es
posible definir varios handlers para varios tipos de excepciones en una misma
declaración try.

try {

} catch(UnTipoDeExcepcion excepcion) {

} catch(OtroTipoDeExcepcion otraExcepcion) {

} catch(YOtroTipoMasDeExcepcion yOtraExcepcionMas) {

}

De esta forma se ejecutará solamente el primer handler asociado al tipo de


excepción que ocurra. Si hay varios candidatos posibles, por ejemplo, si tenemos
un handler para una subclase de una clase de excepción que también queremos
manejar, entonces se ejecuta el primero definido. Por eso, los tipos más
abstractos se definen por último. Cabe aclarar que dentro del bloque del
manejador, solo se puede acceder a las variables declaradas fuera del try y al
objeto excepción definido en el catch correspondiente. Java provee una gran
variedad de excepciones incluidas en el sistema que es recomendable aprender y
usar antes de crear nuevas excepciones.

Algunas de las excepciones más utilizadas son:

Excepción Uso
IllegalArgumentException Parámetro no nulo inválido.
IllegalStateException El objeto receptor se encuentra en un estado
inválido para ejecutar el método.
NullPointerException Parámetro nulo.
IndexOutOfBoundException Parámetro para usar como índice en una
colección es inválido
92

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Cuando queremos crear nuestras propias excepciones, lo más
recomendable es heredar de alguna de las clases ya existentes dentro de la
jerarquía de Exception. Teniendo en cuenta las excepciones ya existentes
podremos ver donde es posible ubicar mejor nuestra nueva clase.

public UsuarioNoExistenteException extends Exception {


// el constructor recibe la información de lo ocurrido
public UsuarioNoExistenteException(String nombre) {…}
// hay métodos para obtener esa información
public String nombreUsado() {…}
}

Es adecuado dotar a nuestra excepción de un constructor que acepte la


información para entender la causa del error y, también, proveer métodos para
acceder a dicha información en el código de manejo. Por otra parte, es necesario
que tengamos en cuenta que las excepciones pueden ser encadenadas en una
relación causal. Para esto podemos utilizar el constructor para pasar la excepción
que originó el error como parámetro o utilizar el método initCause.

public void ingresarConUsuario(String nombre, String clave) throws


IngresoNoPermitidoException
{
try {

} catch(UsuarioNoEncontradoException e) {
throw new IngresoNoPermitidoException(e);
}
}

Este anidamiento de excepciones es muy útil para abstraer al cliente de una


API de errores internos. Abstraemos las excepciones y arrojamos una más

93

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
significativa a la tarea que representa el método. También logramos disminuir el
acoplamiento al reducir el número de excepciones que arroja un método y que
forzamos a los métodos clientes a atrapar o arrojar. Por último, es aconsejable que
cuando lanzamos excepciones, dejemos a los objetos involucrados en un estado
utilizable. Con esto nos referimos a que, si manipulamos el estado de un objeto y
el método falla, ese estado sea válido en la semántica del objeto, de forma que se
le pueda seguir enviando mensajes y este responda adecuadamente.

Excepciones chequeadas

Las excepciones que pertenecen a la jerarquía de Exception, salvo las que


son RuntimeException, son conocidas como excepciones chequeadas. Son
chequeadas porque el compilador Java fuerza a que se las trate específicamente.
Cuando un método quiere arrojar una excepción de este tipo, debe declararlo en la
firma del método. Para esto se utiliza la palabra clave denominada throws
seguida de las clases de las excepciones que se van a lanzar separadas por
coma.

public Usuario buscarUsuarioCon(Nombre nombre) throws


UsuarioNoExistenteException {

throw new UsuarioNoExistenteException(nombre);

}
public void guardar(Object algo) throws
ObjectoNoGuardableException,
ErrorAlGuardarException {

}

El compilador nos alerta si no declaramos las excepciones en la firma del


método. Otra opción es atrapar la excepción y tratarla. Estas excepciones
representan situaciones de errores esperables por la aplicación y deberían ser
recuperables. Por recuperable entendemos que la aplicación puede tomar
acciones para evitar el error en el futuro. Un ejemplo es si nuestra aplicación
94

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
quiere leer un archivo, le pregunta al usuario por el archivo y resulta que no existe,
entonces una opción sería preguntar de nuevo. Otro ejemplo es si estamos en un
sistema y buscamos un usuario pero este no existe, el sistema podría preguntar si
se desea crear el usuario. Estas excepciones representan errores en el dominio
del problema y son tratables en la mayoría de los casos.

Excepciones no chequeadas

Las excepciones no chequeadas son aquellas que son de tipo


RuntimeException o alguna de sus subclases. Estas excepciones son
silenciosas, el compilador no nos obliga a atraparlas ni a declararlas en las firmas
de los métodos (y por lo tanto no sabemos si un método arroja alguna excepción
de este tipo). Estas excepciones representan errores de la aplicación que son
recuperables y generalmente resultan de errores de programación o de lógica en
el programa. Un caso de estas excepciones son las NullPointerException, que
aparecen cuando queremos mandarle un mensaje a null. Resultaría molesto que
por todos lados nos obliguen a tratar o declarar estas excepciones que podrían
ocurrir en cualquier punto donde se envía un mensaje. Si bien es posible atrapar
estos errores y tratarlos, debería ser en casos muy extraños y específicos. En la
mayoría de los casos hay que corregir el error en el programa. Las excepciones
chequeadas forman parte del contrato de un método, en cambio, las no
chequeadas representan qué sucede si se lo rompe.

// no es necesario declararla ni atraparla


public void copiar(String unTexto) {
if(unTexto == null) throw new IllegalArgumentException(“unText”);

}

this.copiar(algo);
// no sabemos que arroja una excepción

Errores

95

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Los errores son problemas que ocurren por fuera de la aplicación y que ésta
no puede ni anticipar ni tratar, generalmente son problemas que encuentra el
runtime con el sistema operativo. Por ejemplo, podemos estar leyendo un archivo
y se rompe el disco desde el cual estamos leyendo el archivo. Otro ejemplo es
cuando el sistema se queda sin memoria para crear nuevos objetos. Recordemos
que este tipo de errores no pueden ser manejados por la aplicación y por esta
razón terminan con el programa siendo abortado. Es necesario tener en cuenta
que los errores son objetos pertenecientes a la jerarquía de la clase Error y sus
subclases. Debemos tener en cuenta que, en casi todos los casos no tenemos que
preocuparnos por este tipo de errores, salvo que estemos desarrollando algún
producto crítico o de bajo nivel como un servidor web o alguna herramienta de
monitoreo de aplicaciones.

96

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
UNIDAD II

2.1.1 Introducción en Bases de datos y SQL

¿Qué es una base de datos? Una base de datos, en su definición más


sencilla, es una colección de archivos relacionados. Imagine un archivo (ya sea en
formato de papel o electrónico) que contenga los pedidos de ventas de una tienda.
También existirá otro archivo de productos, en el que se incluyen los registros
sobre existencias. Para completar un pedido, necesitara buscar el producto en el
archivo de pedidos y los niveles de existencias relativos a dicho producto en el
archivo de productos. Todo esto, ordenado y organizado es a lo que nos
referimos.
Una base de datos y el software que controla la base de datos, denominado
sistema de administración de base de datos (DBMS), le ayudará a realizar
éstas tareas. La mayor parte de las bases de datos actuales son de tipo
relacional. Se denominan así porque utilizan tablas de datos relacionadas por un
campo en común.
En nuestro caso más específico, MySQL es un sistema de administración
de bases de datos relacional (RDBMS). Se trata de un programa capaz de
almacenar una enorme cantidad de datos de gran variedad y de distribuirlos para
cubrir las necesidades de cualquier tipo de organización, desde pequeños
establecimientos comerciales a grandes empresas y organismos administrativos.
MySQL compite con sistemas RDBMS propietarios conocidos, como
Oracle, SQL Server y DB2. MySQL incluye todos los elementos necesarios para
instalar el programa, preparar diferentes niveles de acceso de usuario, administrar
el sistema, protegerla y hacer volcados de datos. Puede desarrollar sus propias
aplicaciones de base de datos en la mayor parte de los lenguajes de programación
utilizados en la actualidad y ejecutarlos en casi todos los sistemas operativos,
incluyendo algunos de los que probablemente no ha oído nunca hablar. MySQL
utiliza el Lenguaje de Consulta Estructurado SQL (Structured Query
Language). Se trata del lenguaje utilizado por todas las bases de relacionales,

97

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
que presentaremos en una sección posterior. Este lenguaje permite crear bases
de datos, así como agregar, manipular y recuperar datos en función de criterios
específicos.

MySQL ha ganado durante el tiempo gran aceptación por una serie de


particularidades / características:

• Está desarrollado en C/C++.


• Se distribuyen ejecutables para cerca de diecinueve plataformas diferentes.
• La API se encuentra disponible en C, C++, Eiffel , Java, Perl, PHP, Python,
Ruby y TCL.
• Está optimizado para equipos de múltiples procesadores.
• Es muy destacable su velocidad de respuesta.
• Se puede utilizar como cliente-servidor o incrustado en aplicaciones.
• Cuenta con un rico conjunto de tipos de datos.
• Soporta múltiples métodos de almacenamiento de las tablas, con
prestaciones y rendimiento diferentes para poder optimizar el SGBD a cada
caso concreto.
• Su administración se basa en usuarios y privilegios.
• Se tiene constancia de casos en los que maneja cincuenta millones de
registros, sesenta mil tablas y cinco millones de columnas.
• Sus opciones de conectividad abarcan TCP/IP, sockets UNIX y sockets NT,
además de soportar completamente ODBC.
• Los mensajes de error pueden estar en español y hacer ordenaciones
correctas con palabras acentuadas o con la letra ’ñ’.
• Es altamente confiable en cuanto a estabilidad se refiere.

Limitaciones de MySQL:

Al comprender sus principios de diseño, se puede explicar mejor las


razones de algunas de sus carencias. Por ejemplo, el soporte de transacciones o
la integridad referencial (la gestión de claves foráneas) en MySQL está
condicionado a un esquema de almacenamiento de tabla concreto, de forma que
si el usuario no va a usar transacciones, puede usar el esquema de
almacenamiento “tradicional” (MyISAM) y obtendrá mayor rendimiento, mientras
98

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
que si su aplicación requiere transacciones, deberá usar el esquema que lo
permite (InnoDB), sin ninguna otra restricción o implicación.

Otras de las limitaciones son las siguientes:

• No soporta procedimientos almacenados hasta la versión 5.0.


• No incluye disparadores hasta la próxima versión 5.0.
• No incluye vistas hasta la versión 5.0.
• No incluye características de objetos como tipos de datos estructurados
definidos por el usuario, herencia, etc.

2.1.2 Desarrollo e implementación de bases de datos

Creación de tablas:

Una vez realizada la conexión con el servidor MySQL y después de abrir


una base de datos, podemos crear tablas en ella de la siguiente manera:

mysql> create table personas (


-> nombre char(30),
-> dirección char(40),
-> teléfono char(15)
-> );
Query OK, 0 rows affected (0.02 sec)

En este caso, la sentencia create table construye una nueva tabla en la


base de datos en uso. La tabla contiene tres columnas, nombre, dirección y
teléfono, todas de tipo carácter y de longitudes 30, 40 y 15 respectivamente. Si se
intenta guardar en ellas valores que sobrepasen esos límites, serán truncados
para poderlos almacenar. Por ese motivo, es importante reservar espacio
suficiente para cada columna. Si se prevé que muchos registros ocuparán sólo
una fracción del espacio reservado, se puede utilizar el tipo varchar, similar a
char, con la diferencia de que el valor ocupará un espacio menor al especificado si
99

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
la cadena es más corta que el máximo indicado, ahorrando así espacio de
almacenamiento.

Eliminación de tablas:

mysql> drop table personas;


Query OK, 0 rows affected (0.01 sec)

Alternativamente, se puede utilizar la sintaxis siguiente:

mysql> drop table if exists personas;

mysql> create table personas (


-> nombre varchar(40) not null
null,
-> dirección varchar(50) null
null,
-> edo_civil char(13) default ’Soltero’,
-> num_registro int primary key auto_increment
auto_increment,

100

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
-> );
Query OK, 0 rows affected (0.01 sec)

En este caso la tabla contiene cuatro columnas, de las cuales nombre y


edo_civil permiten valores nulos, en edo_civil está implícito al no declarar lo
contrario. La columna num_registro no acepta valores nulos porque está definida
como clave primaria.

Tipos de datos:

MySQL cuenta con un rico conjunto de tipos de datos para las columnas,
que es necesario conocer para elegir mejor cómo definir las tablas. Los tipos de
datos se pueden clasificar en tres grupos:

• Numéricos.
• Cadenas de caracteres
• Fechas y horas

El valor null es un caso especial de dato, ya que al significar ausencia de


valor se aplica a todos los tipos de columna. Los siguientes símbolos se utilizan
en la definición y descripción de los tipos de datos en MySQL:

• M - El ancho de la columna en número de caracteres.


• D - Número de decimales que hay que mostrar.
• L - Longitud o tamaño real de una cadena.
• [ ] - Lo que se escriba entre ellos es opcional.

Numérico, los tipos de datos numéricos comprenden dos categorías, los


enteros y los números con punto flotante.

Números enteros. La principal diferencia entre cada uno de los tipos de


enteros es su tamaño, que va desde 1 byte de almacenamiento hasta los 8 bytes.

101

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Las columnas de tipo entero pueden recibir dos atributos adicionales, que deben
especificarse inmediatamente después del nombre del tipo:
Unsigned o sin signo
signo.. Indica que el entero no podrá almacenar valores
negativos. Es responsabilidad del usuario verificar, en este caso, que los
resultados de las restas no sean negativos
negativos,, porque MySQL los convierte en
positivos.

Zerofill.. Indica que la columna, al ser mostrada, rellenará con ceros a la


izquierda los espacios vacíos. Esto de acuerdo al valor especificado por M en la
declaración del tipo. Una columna con el atributo zerofill es al mismo tiempo
unsigned aunque no se especifique.

create table números (


x int(4) zerofill not null,
y int(5) unsigned
);

El comando anterior crea una tabla con dos columnas. Ambas ocuparán un
espacio de 4 bytes, pero al mostrarse, la columna x ocupará un espacio de 4
dígitos y la columna y,, de 5. Tanto zerofill como unsigned deben escribirse
siempre antes que cualquier otro atributo de columna.

102

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Punto flotante, MySQL cuenta con los tipos float y double,, de 4 y 8 bytes
de almacenamiento. Además
emás incluye el tipo decimal, que se almacena como una
cadena de caracteres y no en formato binario.

Cadena de caracteres:

Si observamos la tabla, vemos que el único tipo de dato que siempre utiliza
el tamaño especificado por M es el tipo char. Por este motivo, se ofrece el tipo
varchar que ocupa sólo el espacio requerido por el valor de la columna.

103

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
create table persona(
comentario char(250),
recado varchar(250)
);

La columna comentario ocupará 250 bytes de espacio de almacenamiento,


sin importar el valor almacenado. Por el contrario, la columna recado ocupará sólo
el espacio necesario según el valor asignado; por ejemplo, la cadena “Instalar

MySQL”” tiene 14 bytes de longitud, y el campo recado ocuparía 15 bytes para
almacenarla.

Los tipos text y blob son equivalentes, pero text respeta las mayúsculas,
minúsculas y caracteres acentuados en la ordenación.

create table persona(


edo_civil enum(’soltero’,’casado’,’viudo’,’divorciado’)
(’soltero’,’casado’,’viudo’,’divorciado’)
);

La columna edo_civil de la tabla en la sentencia anterior, solo podrá


almacenar los valores ’’soltero’, ’casado’, ’viudo’, ’divorciado
divorciado’, que son
especificados por el tipo enum. La columna ocupará el espacio de un byte, ya que
los valores enum son representados internamente por números.

Fechas y Horas:

104

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Modificar tablas:

Agregar y Eliminar columnas, alterar la estructura de una tabla es una


tarea más frecuente de lo que uno puede imaginar en un principio. La sentencia
alter table permite una amplia gama de formas de modificar una tabla. La
siguiente sentencia nos recuerda un poco a la estructura de la sentencia create
table, en donde modificamos la tabla personal creada en la sección anterior.

mysql> alter table personal add (


-> mascota char(30) default ’perro’,
-> pasatiempo char (20) not null
-> );

Después de ejecutar la sentencia anterior, aparecen dos nuevas columnas


en la tabla. Si queremos agregar una sola columna, podemos usar la siguiente
sintaxis:

mysql> alter table personal add capital int not null


-> after nom;

Este formato de alter table permite, además, insertar las columnas antes
(before) o después (after) de una columna en cuestión. Las columnas no
deseadas pueden eliminarse con la opción drop.

mysql> alter table personal drop pasatiempo;

105

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Modificar columnas:

La modificación de una columna con la opción modify es parecida a volver a


definirla.

mysql> alter table personal modify


-> mascota char (14) default ’gato’;

Después de la sentencia anterior, los atributos y tipo de la columna han


cambiado por los especificados. Lo que no se puede cambiar con esta sintaxis es
el nombre de la columna. Para ello, se debe utilizar la opción change:

mysql> alter table personal change nom


-> nombre char(20);

La columna que se llamaba nom cambia a nombre. Con el mismo


comando alter table podemos incluso realizar la ordenación física de una tabla
bajo una columna específica:

mysql> alter table personal order by nom;


Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table personal rename gente;

Copiar tablas:

Aunque no existe un comando explícito para copiar tablas de una base de


datos a otra, es posible utilizar el comando rename table para este propósito;
basta con especificar la base de datos a la que pertenece una tabla:

106

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
mysql> rename table base_uno.tabla to base_dos.tabla;

También es posible crear una tabla nueva con el contenido de otra ya


existente (copiando los datos):

mysql> create table nueva_tabla select * from otra_tabla;

La siguiente sentencia es equivalente, pero no copia los datos de la tabla


origen:

mysql> create table nueva_tabla like otra_tabla;

Modificación de filas:

Para la manipulación de filas disponemos de las sentencias SQL Insert,


Update y Delete, su uso y sintaxis ya se ha visto en el módulo 3 de este curso.

En algunos casos, MySQL nos proporciona extensiones o modificadores


que nos pueden ayudar mucho en determinadas situaciones.

• INSERT [DELAYED]. Cuando la sentencia INSERT puede tardar mucho en


devolver el resultado (tablas muy grandes o con muchos índices que deben
recalcularse al insertar una nueva fila) puede ser interesante añadir la
palabra clave DELAYED para que MySQL nos devuelva el control y realice
la inserción en segundo plano.
• INSERT [[LOW_PRIORITY] | [HIGH_PRIORITY]]. En tablas muy
ocupadas, donde muchos clientes realizan consultas constantemente, una

107

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
inserción lenta puede bloquear al resto de clientes durante un tiempo.
Mediante estos modificadores podemos variar este comportamiento.
• INSERT [IGNORE]. Este modificador convierte los errores de inserción en
avisos. Por ejemplo, si intentamos insertar una fila que duplica una clave
primaria existente, el SGBD nos devolverá un aviso (y no insertará la nueva
fila), pero nuestro programa cliente podrá continuar con su cometido si el
resultado de la inserción no era importante para su correcta ejecución.
• UPDATE [LOW_PRIORITY] [IGNORE]. Se comportan de igual modo que
en la sentencia INSERT.
• DELETE [QUICK]. Borra el/los registros sin actualizar los índices.
• TRUNCATE. Es una forma muy rápida de borrar todos los registros de una
tabla, si no necesitamos saber el número de registros que ha borrado.
DELETE FROM <tabla> realiza el mismo cometido, pero devuelve el
número de registros borrados.
• LAST_INSERT_ID(). Devuelve el último identificador asignado a una
columna de tipo AUTO_INCREMENT después de una sentencia INSERT.

2.1.3 Instalación y configuración de plataforma MySQL (guía práctica)

La instalación de MySQL no representa mayores problemas, ya que


muchas distribuciones incluyen paquetes con los que realizar la instalación y
configuración básica resulta ser sencilla. Sin embargo, aquí veremos la instalación
de MySQL utilizando el código fuente que se puede obtener en www.mysql.com.
Cabe destacar que el uso de una versión de MySQL compilada tiene la ventaja de
que, probablemente, se adaptará mucho mejor al entorno del servidor donde se
ejecutará, proporcionando así un mejor rendimiento. Por contra, implicará más
trabajo en caso de que surjan errores en la versión y tengamos que actualizarla.

El sitio de descarga junto con las instrucciones para la instalación serán


publicadas junto con la clase que corresponde a éste tema.

108

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Root:

¿Qué es un root? Un usuario llamado root es el que posee todos los


privilegios sobre todas las bases de datos que se creen en el sistema. Al
comenzar a trabajar con una base de datos, lo primero que debemos hacer
es establecer una contraseña para nuestro usuario root ya que, de no
hacerlo, nuestros datos estarían en peligro ante cualquier visita inesperada.

En las siguientes líneas verán algunos TIPS importantes a tener presente:

En primer lugar, debemos asegurarnos de que contamos con las librerías y


utilidades necesarias para compilar los ficheros fuente. Principalmente la lista de
verificación debe incluir los ficheros siguientes:

• Compilador gcc
• Librerías libgc

El proceso de instalación incluye los siguientes pasos:

• Descomprimir los archivos fuente

cd /usr/local/src
tar xzvf mysql-VERSION.tar.gz
cd mysql-VERSION

Configurar la versión de MySQL que vamos a obtener. El script 'configure'


admite muchos parámetros que deberemos examinar mediante la opción '--help'.
Según los esquemas de tabla que necesitemos o extensiones muy concretas que
debamos utilizar, deberemos examinar con cuidado sus opciones.

109

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
En su versión más simple lo ejecutaríamos de la siguiente manera:

./configure –prefix=/usr/local/mysql

Compilar. Procederemos a compilar si no ha habido problemas con la


configuración.

El parámetro -prefix especifica la ruta del sistema de ficheros donde será


instalado.

Make

Instalar el sistema el servidor ya compilado, mediante la siguiente


instrucción:

make install

Crear la base de datos inicial del servidor, la que almacenará los usuarios y
privilegios. Esta base de datos es imprescindible para que los usuarios se puedan
conectar al servidor.

scripts/mysql_istall_db

Crear un nuevo usuario y su grupo, para que el servicio se ejecute en un


entorno de privilegios restringido en el sistema operativo. En ningún caso se
recomienda que el usuario que ejecute el servicio mysqld sea root.

110

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
groupadd mysql
useradd -g mysql mysql

Todos los archivos deben ser propiedad de root (mysql no debe poder
modificarse a sí mismo) y del grupo mysql. El directorio de datos será del usuario
mysql para que pueda trabajar con las bases de datos, ficheros de registro, etc.

chown -R root /usr/local/mysql


chgrp -R mysql /usr/local/mysql
chown -R mysql /usr/local/mysql/var

Crear el archivo de configuración. La distribución incluye varios archivos de


configuración que sirven como plantilla para adaptarlo a nuestras necesidades. En
este caso, utilizamos la configuración media como plantilla.

Opcionalmente podemos editar el archivo /etc/my.cnf

cp support-files/my-medium.cnf /etc/my.cnf

Lanzar el servidor

/usr/local/mysql/bin/mysql_safe &

En este estado, el servidor no puede servir aún de SGBD. Por defecto,


tendremos creado un usuario 'root' sin contraseña que podrá acceder tanto desde
el equipo local como remotamente. El siguiente paso será asignar una contraseña
111

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
a este usuario y repasar los usuarios y privilegios definidos. Para asignar la
contraseña, deberemos hacer lo siguiente:

mysqladmin -u root password “nuevapasswd”


mysqladmin -u root -h host_name password “nuevapasswd”

Podemos probar el funcionamiento del SGBD conectando con el cliente


'mysql':

mysql -u root –p

Veamos ahora algunas características del servidor que acabamos de


instalar:

• mysqld. El primer método es lanzarlo directamente, se le pueden


especificar las opciones que el administrador desee.
• mysqld_safe. Es un script que ejecuta mysqld garantizando una
configuración segura. Es mucho más recomendable que ejecutar mysqld
directamente.
• mysql_server. Es un guión que realiza dos tareas: iniciar y detener el
servidor mysqld con los parámetros start y stop respectivamente. Utiliza
mysqld_safe para lanzar el servidor mysqld. No es común encontrarlo con
ese nombre, ya que generalmente se copia como el archivo / etc / init.d /
mysql.
• mysql_multi. Permite la ejecución de múltiples servidores de forma
simultánea.

112

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Para detener el servidor básicamente tenemos dos métodos:

• /etc/init.d/mysql stop. Es el mecanismo estándar en los sistemas tipo UNIX.


Aunque los directorios pueden cambiar.

• $ mysqladmin -u root -p shutdown. Es la utilidad para realizar tareas


administrativas en un servidor MySQL, en este caso le pasamos el
parámetro 'shutdown' para detener el servicio.

Para que los mensajes del servidor aparezcan en español, se debe ejecutar
con el parámetro -language:

$ mysqld --language=spanish

Otra opción es agregar en el archivo /etc/my.cnf una línea en la sección [mysqld]

[mysqld]
language = /usr/share/mysql/spanish

2.1.4 Conexión de base de dato con aplicación en JAVA

El equipo en el que se ejecuta MySQL y que almacena los datos se


denomina servidor MySQL. Para establecer una conexión a este servidor,
dispone de varias opciones de instalación. En primer lugar, puede instalar el
cliente y el servidor MySQL en su equipo de escritorio, como ilustra la primera
figura. En segundo lugar, puede instalar el cliente MySQL en su equipo de
sobremesa y el servidor MySQL en otro equipo al que se establecerá la conexión,
113

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
como se ilustra en la segunda figura. Por último, su equipo de sobremesa puede
ser cualquier ordenador que se conecte a otro equipo con un cliente MySQL
instalado, que a su vez se conectara al servidor MySQL, situado en el mismo
equipo o en otro.

(Nuestro equipo tiene instalado el cliente MySQL y el servidor MySQL)

(Nuestro equipo tiene instalado el cliente MySQL. El servidor MySQL se encuentra


instalado en otro equipo al que se conecta el nuestro)

(En éste caso, nuestra terminal puede ser cualquier equipo capaz de conectarse a
otro, ya que ni siquiera lleva instalado el cliente MySQL)

114

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Si el cliente MySQL no se encuentra instalado en su equipo de sobremesa y
necesita conectarse a un segundo equipo para utilizar el cliente MySQL, es
probable que necesite utilizar Telnet o un Cliente Secure Shell (SSH) para
realizar la conexión.

Para ello, basta con abrir el programa Telnet, introducir el nombre del
anfitrión, un nombre de usuario y una contraseña. Si no tiene claro cómo hacerlo,
consulte al administrador de su sistema o bien a través de tutoriales en la red.

Ahora bien, para poder lograr integrar tanto MySQL con JAVA de
Eclipse es necesario recurrir a un paquete de instalación externo. El mismo
podrán encontrarlo en la Clase correspondiente a éste apartado y será muy
sencilla su instalación y uso.

2.1.5 Lenguaje SQL. Definiciones y uso (teoría y práctica)

Operadores

Los operadores son los bloques con los que se construyen las consultas
complejas. Los operadores lógicos (como AND y OR) permiten asociar varias
condiciones de distintas formas. Los operadores aritméticos (como + o *)
permiten realizar operaciones matemáticas básicas en sus consultas. Los
operadores de comparación (como > o <) permiten comparar valores y restringir
los conjuntos de resultados. Por último, los operadores bit n bit, aunque no se
utilicen habitualmente, permiten trabajar con bits en las consultas.

Operadores lógicos

Los operadores lógicos reducen las opciones a true (1) o false (0). Por
ejemplo, si le pregunto si es hombre OR mujer (estoy asumiendo que quiero una
respuesta afirmativa o negativa), la respuesta será si o true. Si la pregunta fuera si

115

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
es hombre AND mujer, la respue
respuesta
sta seria no, o false. Los operadores AND y OR
utilizados en las preguntas son operadores lógicos.

Operadores aritméticos

Los operadores aritmé


aritméticos se usan para realizar operaciones aritméticas
aritmé
elementales. Por ejemplo, en la expresió
expresión 2 + 3 = 5, el signo más
má (+) es un
operador aritmético. En las siguientes tablas se describen los s operadores
aritméticos
ticos disponibles en MySQL.

116

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Operadores de comparación

Los operadores de comparació


comparación se utilizan para realizar
zar comparaciones
entre valores. Por ejemplo,
jemplo, podemos afirmar que 34 ess mayor que 2. La expresión
es mayor que es un operador de com
comparación. La tabla siguiente lista y describe
los operadores de comparació
comparación utilizados en MySQL

117

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Operadores Bit a Bit

Para entender cómo mo funcionan las operaciones bit a bit, es necesario


conocer un poco los números
meros booleanos y la aritmética booleana. Este tipo de
consulta no se suele utilizar
utilizar. En la tabla siguiente se describen los
s operadores bit
a bit.

Uso del Insert Select

La instrucciónn INSERT también n permite agregar registros, o partes de


registros, de otras tablas. Por ejemplo, supongamos que desea crear una nueva
tabla que contenga los nombres de los clientes y lo
los
s valores de todas las compras
realizadas. La consulta para devolver los resultados deseados será la siguiente:

118

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
mysql>SELECT first-name, surname, SUM(value)FROM sales NATURAL J O M
customer GROUP BY first-name, surname;

+- +-+- +

I first-name 1 surname I SUM(va1ue) I

+-+------+- +

I Johnny I Chaka-Chaka I 500 1


I Patricia I Mankunku I 450 1
I Winston I Powers I 750 1
I Yvonne I Clegg I 5800 1

+- +-+------ +

En primer lugar, necesitaremos crear la tabla para que reciba los siguientes
resultados:

mysql> CREATE TABLE customer~sales~values(first~name


VARCHAR (30) , surname VARCHAR (40) , value INT) ;

A continuación, se insertan los resultados en la tabla:

mysql> INSERT INTO customer~sales~values(first~name,surname,value)


SELECT firs t-name , surname, SUM (value) FROM sales NATUR?& JOIN
customer GROUP BY first-name, surname;

119

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
La tabla customer - sales - values contiene ahora los siguientes elementos:

mysql> SELECT * FROM customer~sales~values;

+------+------ +-+

I first-name I surname I value I

+--- +- +-+

I Johnny I Chaka-Chaka 1 500


I Patricia I Mankunku 1 450
I Winston I Powers 1 750
I Yvonne I Clegg 1 5800

+------+------ +-+

Más sobre la agregación de registros

INSERT también permite una sintaxis similar a la utilizada por una


instrucción.

UPDATE.

En lugar de utilizar la siguiente secuencia:

mysql> INSERT INTO customer-sales-values (f irst-name , surname, value)


VALUES ( 'Charles ' , 'Dube' , 0) ;

120

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Podríamos utilizar esta otra:

mysql> INSERT INTO customer~sales~valueSsE T first-name =


'Charles', surname='Dubel, value=O;

También se puede llevar a cabo una forma limitada de cálculo al agregar


registros. Para demostrarlos, agregue otro campo sobre la tabla customer-
salesvalue:

mysql> ALTER TABLE customer-sales-values ADD value2 INT;

A continuación, puede insertar elementos dentro de esta tabla y completar


value2 con el doble del valor:

mysql> INSERT INTO customer-sales-values (f irst-name, surname,


value, value2) VALUES ('Gladys', 'Malherbe', 5, value*2) ;

Este registro contiene 10s siguientes elementos:

mys ql> SELECT * FROM cus tomer-sales-values WHERE


first-name='Gladyst ;

+-------- +- +-+- +

I first-name I surname I value I value2 I

+--- +- +-+- +

121

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
I Gladys I Malherbe I 5 1 10 1

Uso del DELETE y TRUNCATE

Ya sabe cómo eliminar un registro con la instrucción DELETE. Y ya sabrá


que si no utiliza una clausula WHERE se eliminaran todos los registros. Un
problema asociado a la eliminación de registros utilizando este método es que
puede resultar muy lento si la tabla es de gran tamaño. Por suerte, existe otra
forma de realizar dicha operación.

En primer lugar vamos a eliminar todos 10s registros de la tabla customer -


sales - value con la instrucción DELETE.

mysql> DELETE FROM customer~sales~values;


Query OK, 7 rows affected (0.00 sec)

La forma más rápida de eliminar estos valores consiste en utilizar la


instrucción TRUNCATE. A continuación, volveremos a agregar los registros y
utilizaremos dicha instrucción:

mysql> INSERT INTO cus tmr-sales-values (f irst-nam=, surname, value,


value2) VALUES ( 'Johnny' , ' Chaka-Chaka' , 500, NULL) , ( 'Patricia' ,
'Mankwku' , 450, NULL) , ( 'Winston' , 'Powers ' , 750, NULL) , ( 'Yvonne' ,
'Clegg' , 5800, NULL) , ( 'Charles ' , 'Dube' , 0, NULL) , ( 'Charles ' ,
'Dubel, 0, NULL), ('Gladys', 'Malherbe1, 5, 10);
mysql> TRUNCATE customer-sales-values;
Query OK, 0 rows affected (0.00 sec)

Observe la diferencia entre el resultado de las dos instrucciones. DELETE


nos informa del número de filas que se han eliminado, cosa que no hace

122

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
TRUNCATE. Por tanto, TRUNCATE elimina el conjunto completo sin contar los
elementos eliminados. Para realizar esta tarea, elimina la tabla y vuelve a crearla.

2.1.6 Consultas y reportes (teoría y práctica)

Al hablar de consultas sobre la base de datos se ejecutan mediante


sentencias SELECT introducidas en el propio programa cliente y los resultados se
presentan en forma de tabla.

mysql> show tables;


+----------------+
| Tables_in_demo |
+----------------+
| ganancia |
| precios |
| productos |
| proveedores |
+----------------+

Las cuatro tablas representan, de manera ficticia, la base de datos de un


distribuidor de equipos de procesamiento. Están diseñadas para servir de ejemplo
a los casos presentados en este capítulo, por lo que no necesariamente serán
útiles en la vida real.

En nuestro ejemplo imaginario representamos la siguiente situación:

“Nuestro vendedor tiene una relación de proveedores que venden sus productos a
crédito, en efectivo o ambos. Las compras a crédito pagan intereses, pero son
útiles porque no siempre es posible pagar en efectivo. Se utiliza una columna de
tipo conjunto para pago, que puede tomar los valores ’crédito’, ’efectivo’ o
ambos”

123

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
create table proveedores (
empresa varchar(20) not null,
pago set(’crédito’,’efectivo’),
primary key (empresa)
);

Los productos que se distribuyen son partes de equipo de cómputo. Para la


mayoría de los productos en el mercado, los fabricantes sugieren un precio de
venta al público que, aunque no es obligatorio, los consumidores no están
dispuestos a pagar más. Las claves de los productos son asignadas para control
interno con un número consecutivo. Con estas especificaciones, la tabla
productos se define de la manera siguiente:

create table productos (

parte varchar(20),
tipo varchar(20) ,
especificación varchar (20) ,
psugerido float(6,2),
clave int(3) zerofill not null auto_increment,
primary key (clave)
);

La empresa define una política para las ganancias mínimas que se deben
obtener en ventas: el 5% al por mayor y el 12% al por menor. Estos valores se
almacenan en la tabla ganancias, donde se decidió incluir una columna de nombre
factor, con el número por el que se multiplica el precio de compra para obtener el
precio de venta. Los tipos de venta ‘Por mayor’ y ‘Por menor’ se definen con un
tipo de datos enum:

create table ganancia(


venta enum(’Por mayor’,’Por menor’),
factor decimal (2,2)
);

124

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
La lista de precios se define a partir de la empresa proveedor y el producto,
asignándole un precio. Por ese motivo, las columnas empresa y clave se definen
como foreign key.

create table precios (


empresa varchar(20) not null,
clave int(3) zerofill not null,
precio float(6,2),
foreign key (empresa) references proveedores,
foreign key (clave) references productos
);

125

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
UNIDAD III

3.1.1 Introducción al desarrollo visual como interfaz de usuario

¿Qué es una interfaz? Una interfaz en JAVA es, como tal, una simple
declaración de los mensajes que sabe responder un determinado tipo, es decir, es
la declaración del protocolo aceptado por los objetos de ese tipo. Las interfaces no
suplantan a las clases, las complementan. Una clase, que es protocolo más
comportamiento, implementa una o varias interfaces, que solamente son
protocolo. Para implementar un interfaz, una clase tiene que poder responder los
mensajes declarados en ella, ya sea implementándolos o definiéndolos como
abstractos. Las interfaces, al igual que las clases abstractas no pueden tener
instancias directamente. Es posible hacer que una interfaz extienda otra,
requiriendo que la clase que implementa tal interfaz implemente también la que
extiende.

Como ya dijimos, las interfaces declaran la firma de los mensajes, no


contienen implementación alguna. De esta forma estas no sirven para reutilizar
código directamente, pero sirven para otras funciones más importantes.
Tengamos en cuenta que las interfaces sirven para reutilizar código mientras
escapamos de las restricciones propias de la herencia de clases.

Recordemos que en el capítulo anterior dijimos que una característica


deseable de un sistema era el bajo acoplamiento. Podemos reducir el
acoplamiento disminuyendo la cantidad de clases de las cuales dependemos.
También podemos bajar el nivel de acoplamiento haciendo que las dependencias
sean con tipos de protocolo reducido. Los protocolos reducidos no solo alivianan
las dependencias, sino que también hacen que un determinado tipo sea más
entendible, ya que tenemos que comprender menos mensajes para saber cómo
responde un objeto. Las interfaces son artefactos que permiten agrupar mensajes
relacionados y separarlos de otros mensajes no relevantes para una determinada
funcionalidad. Una clase que implementa varias interfaces tiene la capacidad de
responder a varias funcionalidades. Pero los clientes de dicha clase no tienen por
126

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
qué saber todo lo que ella puede hacer, los clientes solamente deben conocer la
interfaz que les interesa y nada más. Así evitamos engrosar las dependencias
entre los elementos, ya que los clientes son independientes de los cambios que
puedan ocurrir en los otros mensajes.

Para Java, las interfaces también son tipos como los son las clases, por lo
tanto los objetos pertenecen tanto al tipo determinado por su clase, así como
también, a los tipos establecidos por las interfaces que implementan. Estos forman
jerarquías que no siguen la línea de las clases, sino que hay una jerarquía por
interfaz y por las clases que las implementan. De esta forma podemos decir que
se trata de una relación de tipos que es transversal a la clasificación.

3.1.2 Desarrollo e implementación de interfaz

Implementación de una Interfaz en JAVA

Para definir una interfaz en Java utilizamos la palabra interface en vez de


class. Así mismo acepta los distintos modificadores de visibilidad.

public interface Mensaje {



}

Ahora la definición del protocolo se realiza con las firmas de los métodos,
sin cuerpo, de igual forma que cuando definimos un método abstracto. Por
definición, todos los métodos indicados en una interfaz son abstractos, por lo que
utilizar este modificador es redundante. Así mismo ocurre con la visibilidad de los
métodos, todos son públicos.

public interface Mensaje {


Destinatario destinatario();

}
127

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Eclipse nos facilita la tarea de crear una interfaz desde cero. Para ello
hacemos clic en el menú File o sobre el botón de New en la barra de
herramientas. También podemos hacer clic con el botón secundario del mouse y
seleccionamos New…/Interface
New…/Interface. Elegimos la carpeta donde se encuentran los
archivos fuentes del proyecto y el paquete de destino, luego ingresamos el nombre
de la interfaz y seleccionamos posibles interfaces a extender. Para terminar
presionamos Finish.

En las interfaces no se pueden definir atributos de instancia, solamente


métodos. Tampoco se pueden definir métodos estáticos. Lo único que se puede
definir en una interfaz, además del protocolo, es una constante. Las constantes
son atributos públicos y estáticos, generalmente se escriben totalmente
total en
mayúscula y se los marca como fina
final.
128

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
public interface MiInterfaceConConstantes {
static final double PI = 3.14d;

}

Igual que en el caso del protocolo, el atributo public es redundante ya que


todo en una interfaz corresponde a público. Como dijimos anteriormente, una
interfaz no hereda de otra (o de muchas otras), sino que la extiende. Cuando una
interfaz extiende a otra, amplia el protocolo definido por esta con nuevos métodos.

public interface Email extends Mensaje {


… // defino nuevo mensajes
}

Es necesario tener en cuenta que antes de que aparecieran las anotaciones


en Java, uno de los usos de las interfaces era para marcar a las clases con
información. Un ejemplo que está en el SDK es la Interfaz Serializable. Estas
interfaces de marca están absolutamente vacías y solo aportan por su presencia.
En este sentido debemos tener en cuenta que en la actualidad lo mejor es utilizar
anotaciones para este propósito, ya que se trata de una opción más poderosa.

Si bien se utiliza la misma palabra, extends, para extender una interfaz y


para heredar de una clase, la semántica es bien distinta. En un caso extendemos
un protocolo, en el otro se crea una jerarquía de clases, sin necesidad de extender
protocolo. Cuando una clase quiere implementar una o varias interfaces lo hace
mediante la palabra implements, seguida de los nombres de las interfaces que
desea implementar separados por coma.

public class EmailSoloTexto implements Email {


@Override // implemento los mensajes de la interfaz
public Destinatario destinatario() {

129

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016

}

}

Al igual que cuando implementamos un método abstracto o sobrescribimos


un método de alguna clase padre, es conveniente anotar el método que
implementa un mensaje de una interfaz con @ Override. También debemos
acordarnos de agregar el modificador de visibilidad public, de esta forma no
romperemos el contrato con la interfaz, ya que es necesario que sea público. Es
posible utilizar una interfaz para definir una clase anónima en un método. El
mecanismo es el mismo que vimos anteriormente.


Mensaje mensaje = new Mensaje() {
@Override
public Destinatario destinatario() {

}

};

Una forma de saber cuándo debemos crear una interfaz es cuando estamos
programando una clase y sabemos que vamos a necesitar ciertos colaboradores
que todavía no existen. En ese caso es cuando podemos crear una interfaz. Así
nuestra clase compilará habiendo ya creado los artefactos mínimos para eso.

Si queremos definir una interfaz a partir de una clase existente y que ésta la
implemente, Eclipse tiene una funcionalidad para este propósito. Para extraer una
interfaz debemos presionar el botón derecho del mouse sobre el código de una
clase y seleccionamos la opción Refactor / Extract Interface. Luego ingresamos
un nombre para la interfaz y elegimos qué métodos de la clase pertenecerán a
esta, hacemos clic sobre OK.

130

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
3.1.3 Estandarización de interfaces

¿Por qué estandarizar? La estandarización, al igual que éste nuevo


paradigma de programar en lenguaje Java, proviene del hecho de re utilizar
absolutamente TODO lo que sea posible, y es en éste punto en dónde cuanto más
estándar sean los programas, sus est estructuras,
ructuras, nomenclaturas y reglas; más
sencillo será su re implementación junto con prominente reducción de costos de
desarrollo. Es en tal caso que en función del tiempo se han dispuesto ciertas

131

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
“convenciones” como regla general internacional, logrando establecer “patrones” y
“reglamentaciones” para los programadores.

Las convenciones de código son importantes para los programadores


principalmente por las siguientes razones:

• El 80% del coste del código de un programa va a su mantenimiento.


• Casi ningún software lo mantiene toda su vida el auto original.
• Las convenciones de código mejoran la lectura del software, permitiendo
entender código nuevo mucho más rápidamente y más a fondo.
• Si distribuyes tu código fuente como un producto, necesitas asegurarte de
que esté bien hecho y presentado como cualquier otro producto.

Para que funcionen las convenciones, cada persona que escribe software
debe seguir la convención. Todos.

En la clase correspondiente al presente tema, se presentará cierta información y


trabajos para poder desarrollar más a fondo el tema.

3.1.4 Verificación y Validaciones (V&V) para el correcto funcionamiento

¿Para qué verificamos y validamos? El proceso de control es el que


asegura y garantiza que el software cumple con su especificación y satisface las
necesidades del usuario (cliente). A continuación desarrollaremos los conceptos
para poder diferenciarlos.

Definición Verificación:

¿Qué es verificación? La verificación se enfoca en éste caso es la que se


enfoca más al proceso de evaluación del sistema o componentes ya que permite
determinar si los productos de una determinada fase del desarrollo satisfacen las
condiciones impuestas en el inicio de la etapa.

132

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
¿Qué se debe tener en la verificación?

• Consistencia: vigilar que la información sea coherente.


• Precisión: corrección de la sintaxis.
• Completitud: lagunas en capacidad deductiva.

Lo que se hace en la verificación (puntos resumidos):

• Identifica desviaciones con estándares y requerimientos.


• Recolecta datos para mejorar el proceso.
• Verifica que el producto:

Cumpla con los requerimientos.

Cumpla con los atributos de calidad.

Se ajuste a las regulaciones, estándares y procedimientos definidos.

Definición Validación:

La validación también es una evaluación del sistema o de componentes,


solo que es en el transcurso o al final del proceso del desarrollo, es donde se
determina si cumple con lo especificado.

Aspectos en la validación:

• Construir el sistema correcto.


• Evaluar la conformidad con la especificación de requisitos.

Implementación de V&V:

Validación: ¿Estamos construyendo el producto correcto? Se encarga de controlar


si el producto satisface los requerimientos del usuario.

133

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Verificación: ¿Estamos construyendo correctamente el producto? Implica controlar
que conforma su especificación original, y en función de ello se determinan las
desviaciones que surgieron durante su desarrollo.

Análisis y detección de Fallos:

• ¿El software falló?


• No hace lo requerido (o hace algo que no debería).

Orígenes de los fallos:

• Las especificaciones no estipulan exactamente lo que el cliente precisa o


quiere (requisitos faltantes o incorrectos).
• Requerimiento no se puede implementar.
• Faltas en el diseño.
• Faltas en el código.

134

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Lo que se busca es detectar y corregir estas faltas antes de liberar el producto -
Objetivos de V&V:

• Descubrir defectos (para corregirlos).


• Provocar fallas (una forma de detectar defectos).
• Revisar los productos (otra forma de detectar defectos).
• Evaluar la calidad de los productos.
• El probar o revisar el software da una idea de la calidad del mismo
Identificación y Corrección de defectos.
• Identificación de defectos.
• Es el proceso de determinar que defecto o defectos causaron la falla

Corrección de defectos:

• Es el proceso de cambiar el sistema para remover los defectos


Introducción

Ejemplo (I)

• El programa lee tres números enteros, los que son interpretados como
representaciones de las longitudes de los lados de un triángulo. El
programa escribe un mensaje que informa si el triángulo es escaleno,
isósceles o equilátero

• Quiero detectar defectos probando (testeando) el programa

• Posibles casos a probar:

lado1 = 0, lado2 = 1, lado3 = 0 Resultado = error


lado1 = 2, lado2 = 2, lado3 = 3 Resultado = isósceles

• Comparo el resultado esperado con el obtenido

• Si son distintos probablemente haya fallado el programa

• Intuitivamente que otros casos sería bueno probar


135

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
lado1 = 2, lado2 = 3, lado3 = 4 Resultado = escaleno
lado1 = 2, lado2 = 2, lado3 = 2 Resultado = equilátero

¿Porqué estos casos? o Al menos probé un caso para cada respuesta


posible del programa (error, escaleno, isósceles, equilátero). Más adelante
veremos técnicas para seleccionar casos interesantes

• Otra forma para detectar defectos es revisar el código

If l1 = l2 or l2 = l3 then
write (“equilátero”)
else ...

En lugar del or me doy cuenta que debería ir un and.


Se puede revisar solo.
Se puede revisar en grupos o Veremos más adelante técnicas conocidas
para revisiones en grupo.

Resumen de Tipos de Faltas:

• En algoritmos
• De sintaxis
• De precisión y cálculo
• De documentación
• De estrés o sobrecarga
• De capacidad o de borde
• De sincronización o coordinación
• De capacidad de procesamiento o desempeño
• De recuperación
• De estándares y procedimientos
• Relativos al hardware o software del sistema

136

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Tipos de Faltas:

• En algoritmos
Faltas típicas o Bifurcar a destiempo o Preguntar por la condición
equivocada o No inicializar variables o No evaluar una condición particular o
Comparar variables de tipos no adecuados

• De sintaxis
Ejemplo: Confundir un 0 por una O
Los compiladores detectan la mayoría

• De precisión o de cálculo
Faltas típicas o Formulas no implementadas correctamente o No entender
el orden correcto de las operaciones o Faltas de precisión como un
truncamiento no esperado

• De documentación
La documentación no es consistente con lo que hace el software
Ejemplo: El manual de usuario tiene un ejemplo que no funciona en el
sistema

• De estrés o sobrecarga
Exceder el tamaño máximo de un área de almacenamiento intermedio
Ejemplos, o El sistema funciona bien con 100 usuarios pero no con 110 o
Sistema que funciona bien al principio del día y se va degradando
paulatinamente el desempeño hasta ser espantoso al caer la tarde. Falta:
había tareas que no liberaban memoria

• De capacidad o de borde
Más de lo que el sistema puede manejar
Ejemplos o El sistema funciona bien con importes <1000000 o Año 2000
sistema trata bien fechas hasta el 31/12/99

• De sincronización o coordinación
No cumplir requerimiento de tiempo o frecuencia.
Ejemplo o Comunicación entre procesos con faltas

137

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
• De capacidad de procesamiento o desempeño
No terminar el trabajo en el tiempo requerido
Tiempo de respuesta inadecuado

• De recuperación
No poder volver a un estado normal luego de una falla

• De estándares o procedimientos
No cumplir con la definición de estándares y/o procedimientos

• De hardware o software del sistema


Incompatibilidad entre componentes

Clasificación de Defectos:

• Categorizar y registrar los tipos de defectos


Guía para orientar la verificación o Si conozco los tipos de defectos en que
incurre la organización me puedo ocupar de buscarlos expresamente
Mejorar el proceso o Si tengo identificada la fase en la cual se introducen
muchos defectos me ocupo de mejorarla

• Clasificación Ortogonal
Cada defecto queda en una única categoría
Si pudiera quedar en más de una de poco serviría

• Clasificación Ortogonal de IBM


Función: afecta capacidad de brindarla, interfaz usuario, de producto, con
hardware o estructura global de datos
Interfaz: al interactuar con otros componentes o drivers vía call, macros,
control blocks o lista de parámetros
Validación: no valida de forma adecuada los datos antes de usarlos
Asignación: falta en inicialización de estructura de datos o bloque
Tiempo / Serialización: recursos compartidos o tiempo real
Build / Package / Merge: problemas en repositorios, control de cambios o
versiones
Documentación: publicaciones o notas de mantenimiento

138

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Algoritmo: involucra eficiencia o correctitud de algoritmo o estructura de
datos, pero no diseño

Pruebas en el Proceso:

• Desempeño
Determina si el sistema integrado, en el ambiente objetivo cumple los
requerimientos de tiempo de respuesta, capacidad de proceso y
volúmenes

• Aceptación
Bajo la supervisión del cliente, verificar si el sistema cumple con los
requerimientos del cliente (y lo satisface)
Validación del sistema

• Instalación
El sistema queda instalado en el ambiente de trabajo del cliente y
funciona correctamente

¿Quién Verifica?

• Pruebas Unitarias:
Normalmente las realiza el equipo de desarrollo. En general la misma
persona que lo implementó.
Es positivo el conocimiento detallado del módulo a probar

• Pruebas de Integración
Normalmente las realiza el equipo de desarrollo
Es necesario el conocimiento de las interfaces y funciones en general

• Resto de las pruebas


En general un equipo especializado (verificadores)
Es necesario conocer los requerimientos y tener una visión global

139

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
¿Por qué un equipo especializado?

Maneja mejor las técnicas de pruebas


Conoce los errores más comunes realizados por el equipo de
programadores
Problemas de psicología de pruebas o El autor de un programa tiende a
cometer los mismos errores al probarlo o Debido a que es “SU” programa
inconscientemente tiende a hacer casos de prueba que no hagan fallar al
mismo o Puede llegar a comparar mal el resultado esperado con el
resultado obtenido debido al deseo de que el programa pase las pruebas

Actitudes Respecto a la Verificación:

• ¿Qué sabemos de un programa si pasó exitosamente un conjunto de


pruebas?

• Orgullo de nuestra obra (como programador) “no es mi culpa”

• Conflictos posibles entre


Encargado de verificación (encontrar faltas)
Desarrollador (mostrar las bondades de su obra)

• Soluciones:
Trabajo en equipo (roles distintos, igual objetivo)
Se evalúa al producto (no la persona)
Voluntad de Mejora (personal y del equipo)

Verificación Unitaria:

• Temario
Técnicas de verificación unitaria
Técnicas estáticas – Análisis o Análisis de código fuente o Análisis
automatizado de código fuente o Análisis formal
Ejecución simbólica
Técnicas dinámicas – Pruebas o Definiciones, proceso para un
módulo, conceptos básicos, teoría o Caja Blanca o Caja Negra
140

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Comparación de las técnicas

• Técnicas de Verificación Unitaria

• Técnicas estáticas (analíticas)


Analizar el producto para deducir su correcta operación

• Técnicas dinámicas (pruebas)


Experimentar con el comportamiento de un producto para ver si el producto
actúa como es esperado

• Ejecución simbólica
Técnica híbrida

• Técnicas Estáticas

• Análisis de código
Se revisa el código buscando defectos
Se puede llevar a cabo en grupos
Recorridas e Inspecciones (técnicas conocidas con resultados
conocidos)

• Análisis automatizado de código fuente


La entrada es el código fuente del programa y la salida es una serie
de defectos detectados

• Verificación formal
Se parte de una especificación formal y se busca probar (demostrar)
que el programa cumple con la misma

Análisis de Código:

• Se revisa el código buscando problemas en algoritmos y otras faltas


• Algunas técnicas:
Revisión de escritorio
141

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Recorridas e Inspecciones o Criticar al producto y no a la persona o
Permiten
Unificar el estilo de programación
Igualar hacia arriba la forma de programar o No deben usarse para
evaluar a los programadores
Recorridas
Se simula la ejecución de código para descubrir faltas
Número reducido de personas
Los participantes reciben antes el código fuente
Las reuniones no duran más de dos horas
El foco está en detectar faltas y no en corregirlas
Los roles clave son: o Autor: Presenta y explica el código o
Moderador: Organiza la discusión o Secretario: Escribe el reporte de
la reunión para entregarle al autor
El autor es el que se encarga de la “ejecución” del código

• Inspecciones:
Se examina el código (no solo aplicables al código) buscando faltas
comunes.
Se usa una lista de faltas comunes (check-list). Estas listas
dependen del lenguaje de programación y de la organización. Por
ejemplo revisan: o Uso de variables no inicializadas o Asignaciones
de tipos no compatibles
Los roles son: Moderador o Encargado de la Inspección, Secretario,
Lector, Inspector y Autor
Todos son Inspectores. Es común que una persona tenga más de un
rol
Algunos estudios indican que el rol del Lector no es necesario.

142

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Estrategias de Integración:

• No incremental
Big-Bang

• Incrementales
Bottom-Up (Ascendente)
Top-Down (Descendente)
Sandwich (Intercalada)
Por disponibilidad

• El objetivo es lograr combinar módulos o componentes individuales para


que trabajen correctamente de forma conjunta

143

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Pruebas de Sistemas OO:

• Temario
Características
Algunos problemas
“Object-Oriented programs and testing” – Perry y Kaiser
Estrategia N+

Características:

• Normalmente son sistemas más complicados de probar (testear)

• Características que lo diferencian de otros sistemas


Encapsulación de la información
Las clases tienen estado y comportamiento. El estado afecta al
comportamiento y el comportamiento afecta al estado. Esto no es común en
lenguajes procedurales
Las unidades son más pequeñas (clases, objetos)
Los métodos son más pequeños
Un sistema OO tiene muchas más integraciones que uno procedural
Herencia, polimorfismo y dynamic binding

Algunos Problemas:

• Debido a la encapsulación de la información


Si tengo que testear un método multX (multiplica al atributo x por el pasado
en el método) de una clase A y ese método cambia el valor del atributo x de
la clase A, ¿Cómo sé si lo cambió correctamente? ¿Es válido confiar en el
método getX de la clase A?

144

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Algunos Problemas:

• Debido a la encapsulación de la información


Si la clase está debidamente testeada se creía (en los primeros tiempos de
la OO) que podría ser usada en cualquier otro sistema comportándose de
manera correcta. Más adelante veremos que esto no es como se pensaba.
En definitiva, una gran bondad de la OO que es la reutilización no se pierde,
sin embargo, hay que volver a testear la integración (esto es debido al
cambio de contexto)

Debido al estado y comportamiento de los objetos:

Cuando un objeto recibe un mensaje no siempre actúa de la misma manera


sino que depende del estado en que este se encuentre (el estado es el
valor de todos los atributos del objeto; incluyendo otros objetos)

Cuando un objeto termina de ejecutar el método, puede ser que su estado


haya cambiado

Esto trae aparejado que los métodos convencionales de testing no pueden


ser aplicados tal cual. Existen métodos que usan diagramas de estado de
clases para realizar pruebas de objetos (vamos a ver uno más adelante,
estrategia N+)

145

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Unidades más pequeñas, métodos más pequeños y mayor integración que
lenguajes procedurales:

Si bien los objetos manejan estados y esto hace distintas las pruebas
respecto a las tradicionales, como los métodos son más pequeños es más
fácil realizar pruebas de caja blanca en OO que en lenguajes procedurales

Por otro lado la cantidad de objetos que interactúan entre sí es mucho más
grande que los módulos que interactúan en un lenguaje procedural

Se considera que la prueba de unidad es más sencilla en sistemas OO pero


las pruebas de integración son más extensas y tienden a ser más
complejas. Debido a herencia, polimorfismo y dynamic binding

Cuando una superclase cambia un método hay que testear la subclase ya


que puede haber introducido inconsistencias en esta última. Esto es sabido
desde “siempre”

Se creía que cuando una clase heredaba de otra que ya estaba


adecuadamente testeada, los métodos heredados no debían ser testeados.
Mostraremos más adelante que este concepto está equivocado “Tiran
abajo” algunos mitos sobre las pruebas de sistemas Orientados a Objetos

Un programa está adecuadamente testeado si a sido cubierto de acuerdo al


criterio seleccionado (el criterio puede ser tanto estructural como funcional)

Encapsulación en clases:

• Mito: Si mantenemos las interfaces de una clase sin cambiar, y cambiamos


la implementación interna manteniendo la misma funcionalidad, no hay que
volver a testear las clases que usan la clase modificada

146

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
• Realidad: El axioma anticomposition nos recuerda la necesidad de volver a
testear también todas las unidades dependientes porque un programa que
fue testeado adecuadamente de forma aislada puede no estar
adecuadamente testeado en combinación. Esto significa que además del
testeo de unidad que hay que realizar en la clase modificada también hay
que realizar testeo de integración

Encapsulación en clases:

Cuando modifico una clase se debe volver a testear esa clase y todas las
que se relacionan explícitamente con esta

Subclases nuevas o modificaciones de subclases:

• Mito: No se deben testear los métodos heredados de la superclase ya que


fueron testeados en esta
• Realidad: El axioma antidecomposition nos dice lo contrario. El uso de
subclases agrega esta inesperada forma de dependencia porque provee un
nuevo contexto para las componentes heredadas.

147

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016
Sobre-escritura de métodos:

• Mito: Al sobre escribir un método heredado se puede testear


adecuadamente la subclase con un test set adecuado para la superclase
• Realidad: Aunque muy probablemente los dos métodos (el de la superclase
y el sobre-escrito en la subclase) computen una función semánticamente
similar un test set adecuado para uno no tiene porque ser adecuado para el
otro. Esto se deduce a partir del axioma antiextensionality

Conclusión más general:

Se revoca la intuición que antes se tenía de que la encapsulación y la


herencia iban a reducir los problemas del testing

Propuesta muy común:

Testing de métodos individuales o Dada la definición funcional de un


método se testea según técnicas que ya vimos

Testing intraclase o Se busca testear la relación entre los métodos de una


clase. Por ejemplo, estrategia N+.

Testing interclases o Similar al test de integración solo que como ya se comento


es más complejo por la cantidad de interacciones

Testing funcional

148

IRSO –Integración de Programación – 2015


Año de creación del módulo: 2016

Anda mungkin juga menyukai