1
Manual para la asignatura de Fundamentos de Programación Versión 1.0. Santiago Marzo de 2012
Este material ha sido diseñado para el uso de los alumnos y profesores de la asignatura de Análisis y Diseño Orientado a Objetos de las carreras del área informática. Queda estrictamente prohibido el uso en otros cursos ya sean en línea o presenciales sin el consentimiento explícito de INACAP.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
2
Agradecimientos. Agradecemos a todas las personas que de forma directa o indirecta han colaborado en la elaboración de este manual. De forma significativa agradecemos a los docentes de las sedes que nos han apoyado y colaborado con ejercicios y propuestas durante la presentación de este proyecto. Vayan nuestros sinceros agradecimientos a los siguientes docentes: Cristian Leiva Marín, Miguel Palma Esquivel, Marcelo Montecinos Cabrera, Rodrigo Toledo de los Santos, Paola Cifuentes Berrios, Servando Campillay Briones, Emerson Ilaja
Villarroel,
Santolaya,
Hugo
Manuel
Herrera
Morales,
Valenzuela,
Roberto
Pérez
Fernando Fuentes,
Fernando Neyra Castro, Victor Bórquez, Francisco Andrés Díaz Rojas, Ademar Araya Fuentes, Ricardo Vera Muñoz, Mauricio Torres Pizarro, Ernesto Ramos Vega, Alberto Garrido Burgos, Helton Bustos Sáez, Beatriz Contreras Guajardo, José Landeta Parra, Luis Pacheco Toro, Patricio Araya Castro, Iván Torres, Hinojoza Vega Mauricio, Yasna Hernández, Víctor Orellana, Rene Valderas Aros, Ricardo Toledo Barría, Cesar Eduardo Arce Jara, Luis Ponce Cuadra, Caballero,
Javier Pedro
Miles
Avello,
Alfonso
Carolina
Fuentealba
Ehrmantraut
Martínez,
Jorge
Hormazabal Valdés, Pedro Ernesto Ulloa Morales, María del Pilar Gallego Martínez, Claudio Fuenzalida Medina, María Encarnación Sepúlveda, Francisco San Martin, Christian Sarmiento Zampillo, Román Gajardo Robles, Ricardo UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
3
Hidalgo Hidalgo, Nelson Fredy Ganga Calderón, Manuel Reveco Cabellos, Jacqueline San Martin Grandon, Sergio Vergara Salvatierra, Pablo López Chacón, Cinthya Acosta, Jocelyn Oriana González Cortés, Carlos Felipe Alten López, Francisco Prieto Rossi, Giannina Costa Lizama, Christian Silva, Sebastián Pastén Díaz.
El aporte realizado por ustedes durante las jornadas de capacitación ha significado mejorar enormemente la calidad del material entregado. Saludos.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
4
Contenidos Fundamentos del procesamiento de datos. ....................................................................................... 8 Conceptos básicos. .......................................................................................................................... 8 Dato ........................................................................................................................................... 10 Proceso ...................................................................................................................................... 10 Información. .............................................................................................................................. 12 Entrada y Salida. ........................................................................................................................ 12 Proceso manual de datos. ......................................................................................................... 13 Proceso computacional de datos. ............................................................................................. 13 Estructura funcional de un computador. ...................................................................................... 14 Dispositivos de entrada y salida. ............................................................................................... 14 Unidades Internas. .................................................................................................................... 15 Unidades externas de almacenamiento secundario. ................................................................ 16 Elementos o componentes de un procesamiento computacional de datos. ....................... ............................... ........ 18 Plantilla para prueba manual o seguimiento de ejecución de una secuencia lógica. .................. .................... 22 Técnicas de algoritmos para el diseño de procesos computacionales. ............... ........................ ................... ................... ........... 26 Conceptos básicos. ........................................................................................................................ 26 Algoritmo. .................................................................................................................................. 26 Programa. .................................................................................................................................. 32 Etapas en la creación de program p rogramas. as. ................................. ............... ................................... .................................. ................................... ...................... 32 Características de la programación. .............................................................................................. 39 Estructura descendente. ........................................................................................................... 39 Modularidad. ............................................................................................................................. 40 Cohesión. ................................................................................................................................... 40 Acoplamiento. ........................................................................................................................... 41 Descomposición. ....................................................................................................................... 42 Estructura de un algoritmo. .......................................................................................................... 43 Conceptos de variables y constantes. ........................................................................................... 44 Definición de variables y constantes. ........................................................................................ 44 Representación de sentencias en Instrucciones. .......................................................................... 60
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
5 Operadores Aritméticos. ........................................................................................................... 60 Operadores unarios y de auto asignación ................................................................................. 61 Operadores Lógicos ................................................................................................................... 62 Introducción a lenguajes formales de Programación. .......................... ................................... .................. .................. .................. ................. ........ 66 Estructura de un programa. .......................................................................................................... 66 Sentencia condicionales ................................................................................................................ 67 Anidada. .................................................................................................................................... 75 Múltiple ..................................................................................................................................... 77 Sentencias de ciclo iterativo .......................................................................................................... 79 While ......................................................................................................................................... 80 For ............................................................................................................................................. 81 Do … While. ...............................................................................................................................
85
Concepto de función ..................................................................................................................... 86 Estructura de una función ............................................................................................................. 89 Procedimientos ......................................................................................................................... 89 Función .......................................................................................................................................... 95 Llamada a una función .................................................................................................................. 97 Relación de la función con el método de una clase. ................................................................... 108 Arreglos ........................................................................................................................................... 108 Unidimensionales .................................................................................................................... 108 Arreglos de dos dimensiones. ..................................................................................................... 111 Arreglos de arreglos. ............................................................................................................... 113 Introducción a la Programación Orientada a Objeto. ................ .......................... ................... .................. .................. .................. ................ ....... 117 Características generales de la programación orientada a objetos. .................. ........................... .................. ................ ....... 117 Qué es la programación orientada a objetos .............................................................................. 117 Atributos ...................................................................................................................................... 119 Comportamientos ....................................................................................................................... 120 Estados ........................................................................................................................................ 121 Clase ............................................................................................................................................ 122 Abstracción .............................................................................................................................. 126 Encapsulación .......................................................................................................................... 127 Herencia .................................................................................................................................. 128 UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
6 Asociación. .............................................................................................................................. 129 Aplicaciones básicas .................................................................................................................... 129 Seguridad en una clase ................................................................................................................ 138 Get y Set. ..................................................................................................................................... 142
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
7
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
8
Fundamentos del procesamiento de datos. A continuación vamos emprender un viaje sólo de ida, no te preocupes no se trata de un trágico final, es sólo de ida porque luego que conozcas todo lo que hay preparado para tí en las páginas venideras no querrás volver atrás. Durante este manual nos encargaremos, con tu ayuda y por supuesto la de tu profesor, de dar los primeros pasos para convertirte en un desarrollador de proyectos de tecnologías de la información, este manual es el primero de varios y en cada uno iremos agregando más dificultad, mayores
novedades
y
elementos
cada
vez
más
sorprendentes.
Conceptos básicos. Ahora
nos
referiremos
procesamiento computacionales
de
a
datos,
tienen
el
los todos mismo
fundamentos los
del
programas
objetivo,
primero
obtener datos de entrada (por lo general desde un usuario), luego los almacena, después realiza algún procesamiento (cálculos, ordenamientos, etc) con ellos y finalmente entrega el resultado. El proceso es muy similar a cuando un detective está interrogando a un sospechoso en las películas, imagina esas típicas salas de interrogatorio y un detective como el de las series de los años ochenta, el cual está de pie y al frente el sospechoso sentado en una silla, cuando el detective se acerque a él, lo mire a los ojos y le diga “smith UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
9
anderson”, el sospechoso recibirá esta información y realizará una búsqueda interna para luego de unos segundos de silencio
dar el paradero de Smith y otra
información relevante para su detención al detective, en este caso lo que el detective hace es recolectar datos durante su caso, pero estos datos por si sólo no permitirán resolverlo, por otra parte los datos son en realidad alguna característica de algo o alguien, Smith por ejemplo, es el nombre nombre de una persona, pelo negro, 34 años, 1.72 metros son también datos que representan a una entidad, pero para que el detective resuelva el caso necesita del sospechoso a quien le dio los datos como una entrada para que así el sospechoso haga algún tipo de procesamiento con los datos, los cuales pueden ser una suma, restas o alguna otra operatoria como por ejemplo una
búsqueda, a partir partir de este procesamiento
interno, el sospechoso logró obtener la dirección de Smith la cual generó como una salida hacia el detective. Lo que ha recibido el detective a cambio de la entrega de datos es información relevante para él. Así como esta situación el software se comporta de forma muy similar piensa los últimos software que has usado, un ejemplo de ello es la calculadora de Windows a la cual le entregas datos de entrada, luego solicitas una operación y presiones el botón igual, esto da como resultado que la calculadora procese los datos y finalmente entregue el resultado. Veamos ahora otro ejemplo, en el caso de un videojuego, el cual parece ser tan distinto a una calculadora sigue los mismos principios, a través del
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
10
joystick el usuario ingresa datos de entrada con los cuales especifica la dirección en la que desea moverse, el software recibe estos datos los almacena y los procesa, al final el software presenta al usuario la información solicitada en la cual el personaje se encuentra ahora en una posición distinta pero de acuerdo a lo que el usuario ha ingresado. Este modelo es muy simple y consta de tres partes, dato, proceso
e
información,
las
cuales
se
definen
a
continuación.
Dato Corresponde a un par ordenado de atributo con valor (atributo, valor) que representan el registro de un hecho importante
para
la
organización
en
un
momento
determinado. Un dato esta compuesto de dos partes, un atributo y un valor, el atributo define que es lo que deseo guardar y el valor define el tipo de valor asociado, es decir el tipo de datos y sus valores máximos y mínimos. Los datos siempre están formados por un par ordenado, ya que, sus partes por separado carecen de sentido.
Proceso Corresponde a la aplicación de cálculos aritméticos, ordenamientos o algún otro tipo de manipulación de los datos y que a partir de ello genera información. UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
11
Veámoslo a través de un ejemplo, supongamos que tienes en tu closet una caja de películas, la forma en la que se han guardado las películas en la caja no ha sido mediante ningún orden, muy por el contrario han sido guardadas en el mismo orden que las has adquirido, por lo que hay dentro de la caja es un completo desorden que hace juego con el resto del closet. Para poder ver la película que tanto anhelas vas a tener que buscarla, este proceso comienza con un dato de entrada, para el cual vas a necesitar el nombre de la película (un dato), el cual puede ser por ejemplo: Nombre película = hoy si estudiaré. A partir de este dato el proceso que debes llevar puede variar según tu forma de hacer las cosas, un posible camino es hacer una comparación, proceso que consiste en tomar las películas una por una e ir comparando su nombre con el de la película que buscas hasta dar con ella,
otro
camino
puede
ser
verificar
si
ellas
se
encuentran ordenadas, de ser así bastará con realizar una búsqueda basado en el alfabeto para dar con ella, de no estar ordenadas entonces podrías ordenarlas, así este proceso será más simple la próxima vez, el resultado de esta
búsqueda
adicionalmente
será un
la
película
buen
consejo
que
deseas
será
ver,
considerar
mantener tu closet ordenado.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
12
Información. Mensaje
válido
para
un
receptor
resultante
del
procesamiento de datos. Debes considerar que no todo lo resultante de un proceso es información si esta no va dirigida a quien corresponde, por ejemplo, si vas caminando por afuera del aeropuerto y un mensaje mensaje que dice
“se informa informa que el vuelo 345
tiene un retraso de 45 minutos”, sin duda eso es información y ha nacido desde el cálculo de la posición del vuelo, vuelo, la distancia con el aeropuerto y la velocidad que lleva, sin embargo para ti que sólo buscas un taxi, esa información no te sirve, por ende deja de ser información para ti.
Entrada y Salida. Como lo mencionamos al inicio los software llevan a cabo principalmente cuatro acciones: recibir datos de entrada, almacenarlos, procesarlos procesarlos y entregar un resultado. resultado. Muchas veces la palabra dato e información son utilizadas indistintamente, pero sin embargo en este contexto son muy distintas. Cuando un usuario interactúa
con un
software es el usuario el que provee de datos al programa, estos datos como la definición lo dice son la representación de una entidad, es decir son datos que representan el valor de una entidad, cuando estos datos son recibidos por el software este los almacena en la memoria, luego los toma, los procesa, es decir realiza algún tipo de cálculo en ellos para luego depositarlos nuevamente en la memoria. Podemos decir entonces que UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
13
dato e información no son lo mismo, debido a que para que los datos se conviertan en información deben haber pasado primero por un procesamiento. En general los datos por si solos no sirven para tomar una decisión en cambio la información sí sirve para tomar decisiones.
Proceso manual de datos. El procesamiento manual ha existido desde siempre y corresponde a toda transformación o cálculo que se realice con datos mediante cálculos mentales o con la utilización de lápiz y papel, esta técnica es muy propensa a errores sobre todo cuando se trata de realizar grandes cálculos o la clasificación y ordenación de un conjunto muy numeroso de datos. Adicionalmente el proceso se lleva a cabo de forma lenta, lo que produce que muchas veces sea una técnica poco viable para las empresas de hoy, las cuales procesan los datos de millones de personas.
Proceso computacional de datos. El proceso computacional en cambio corresponde a la automatización de procesos comunes que en su comienzo solían
hacerse
con
lápiz
y
papel,
las
operaciones
aritméticas básicas fueron un comienzo y así la técnica ha ido refinándose hasta llegar a lo que hoy nos rodea: planillas de Excel, sistemas bancarios para llevar las cuentas de miles de clientes y reconocimiento facial o procesamiento de imágenes son algunos ejemplos, esto nace de la necesidad de que la información debe estar en el momento en que se necesita, imagina qué sucedería si UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
14
tratásemos de llevar el censo de nuestro país utilizando el proceso manual, es probable que cuando los resultado estén listos la información generada no represente en lo absoluto la realidad nacional y por ello lo que en un momento hubiese sido información vital hoy es sólo un dato que no sirve.
Estructura funcional funcional de un computador. Dispositivos de entrada y salida. Si bien un software se basa en el procesamiento computacional información
de
no
datos
con
olvidemos
que
el
fin estos
de
entregar
software
se
almacenan y ejecutan dentro de un computador, es por ello que los computadores deben proveer alguna forma en la que podamos comunicarnos con ellos, todo los computadores poseen lo que se conoce como periféricos los cuales podemos dividir en entrada y salida. Los periféricos de entrada son todos aquellos dispositivos que permiten ingresar información, algunos ejemplos de ello son el teclado a través del cual digitamos, el mouse, un escáner el cual nos permite digitalizar las fotos o alguna imagen, el micrófono que utilizamos para chatear, o dictar un documento a nuestro computador. Los periféricos de salida en cambio son todos aquellos dispositivos
que
permiten
al
computador
emitir
información que ha procesado producto de los datos que UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
15
hemos ingresado, probablemente el más utilizado de todos sea el monitor, en la cual el computador nos muestra la información requerida, otros ejemplos son la impresora, la que nos permite obtener la información en papel o los parlantes, que emiten sonidos según lo que le pidamos o hagamos.
Unidades Internas. En un computador el encargado de procesar toda la información es la Unidad Central de Proceso CPU (Central Processing Unit). Esta unidad es la encargada del control y de la ejecución de las operaciones del sistema, también lo conocemos como el microprocesador. Las actividades que realiza la CPU son:
Ejecutar
las
instrucciones
de
los
programas
almacenados en la memoria.
Controlar la transferencia entre la CPU y la memoria.
Responder a las peticiones realizadas por algún
periférico.
Unidad de control. Coordina las actividades del computador y determina qué operaciones se deben realizar y en qué orden; así mismo controla todo el proceso del equipo.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
16
Unidad Aritmética-lógica Realiza operaciones aritméticas y lógicas, entre las operaciones aritméticas se encuentras las sumas o restas y en las lógicas las comparaciones del tipo mayor, menor, igual, etc.
Unidad de almacenamiento principal. Es la parte de la CPU en la que se encuentran almacenadas las instrucciones y todos los datos que necesarios para llevar a cabo un proceso, esta memoria es temporal, esto quiere decir que si apagas el equipo toda
la
información
alojada
ahí
es
eliminada,
el
procesador usa esta memoria debido a que es un lugar a la que puede acceder más rápido, es por esto que los datos son cargados aquí como paso previo a su ejecución. La unidad de almacenamiento principal es popularmente conocida como memoria RAM.
Unidades externas de almacenamiento secundario. Adicional a los datos que el computador almacena de forma
temporal
para
su
procesamiento,
existen
dispositivos de almacenamiento que permiten que la información perdure en el tiempo y que se encuentran fuera del equipo, algunos ejemplo de ellos son el CD, DVD, blueray o memorias flash, en ellos se almacenan datos que podrán ser procesados más adelante y su almacenamiento es permanente e independiente de si el computador está prendido o apagado. UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
17
Para ayudarte a comprender mejor cómo el computador utiliza los dispositivos de almacenamiento veámoslo con una
simple
analogía.
Supongamos
que
tú
eres
el
procesador y tu misión hoy es recolectar un conjunto de datos históricos para procesarlos y crear con ellos un resumen
de
historia,
el
cual
contiene
información
relevante para quien lo solicitó, muy lejos de la silla y el escritorios donde te encuentras hay un estante llenos de libro, los cuales siempre están allí, este estante es el equivalente al disco duro de tu computador, pero imagina tuvieses que levantarte de la silla, ir hasta el estante, tomar un libro, volver a tu silla, buscar lo que necesitas y luego
volver
a
dejarlo
al
estante
para
luego
complementar el informe con otro libro ¿lento verdad? Entonces al igual que tú, el computador necesita traer un conjunto de datos para mantenerlos temporalmente más cerca, entonces ese rol lo jugará el escritorio, de esta forma te acercarás al estante y traerás en uno o más viajes todos los libros que necesites y lo dejarás sobre tu escritorio, de esta forma no necesitarás levantarte tan seguido, nuestro escritorio es el equivalente a la memoria RAM, por lo que también podemos afirmar que mientras más
memoria
RAM
tengamos
mejor
rendimiento
tendremos, ya que podremos almacenar y dejar más información allí, ahora que mantenemos los datos cerca, para que puedas leer y producir un resumen con tu cerebro (equivalente al procesador de tu PC), necesitarás acercar los libros que tienes en tu escritorio, lo recogerás con la mano para de esta forma logrado acercar más la
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
18
información, así estará lista para ser leída y procesada por tí, tu mano en esta analogía es el equivalente a la memoria cache de tu procesador, cuando hayas finalizado tu informe todo lo que se encuentra en tu mano y escritorio desaparecerá, pero volverá a quedar de forma permanente en tu estante, esto se debe a que tu mano y el
escritorio
almacenan
información
sólo
de
forma
temporal, en el computador la RAM y la CACHE se comportan de la misma forma y existen con el fin de acercar la información hacia el procesador, dado que es más rápida su lectura desde allí, sin embargo este tipo de memoria mientras más rápida suele ser más pequeña, al igual que la proporción entre tu mano, escritorio y estante, que adicionalmente va desde la más asequible a la
más
distante,
siendo
la
mano
la
unidad
de
almacenamiento más pequeña y el estante la más grande.
Elementos o componentes de un procesamiento computacional computacion al de datos. Cuando analices un proceso o un sistema, siempre debes prestar atención a las etapas o acciones que se ejecutan en el sistema que estás analizando. Recuerda que los sistemas están compuestos de una serie de elementos que interactúan entre sí para lograr un propósito. Para lograr este propósito cada uno de los objetos detectados en el proceso realizan un conjunto de acciones. Para UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
19
poder realizar estas acciones, las partes componentes necesitan datos de entrada. Estos datos son la materia prima con la cual los objetos realizan sus acciones. Una vez que reciben los datos, los objetos realizan las acciones para las cuales fueron creados, generando un resultado que se conoce como dato de salida. Podemos analizar las acciones que realiza un objeto como una caja negra es decir sabemos lo que entra y el resultado del proceso pero no lo que sucede adentro. Por ejemplo si utilizo un reproductor de DVD, los datos de entrada están contenidos en el disco que ingreso al equipo, y la salida será la imagen y el audio, pero el proceso es desconocido y por lo demás no me interesa, pues sólo quiero ver el DVD no construir un reproductor. Ahora si mi necesidad aumenta y además de usar un reproductor de DVD ahora quiero construir uno, entonces debo conocer qué es lo que hace el dispositivo con los datos que están en el disco para generar la imagen y el audio, esto se conoce como procesamiento de los datos, el cual básicamente consiste en leer los datos, ordenarlos y guardarlos, procesarlos y finalmente generar una salida. El procesamiento de los datos está asociado a la toma de decisiones, que se estructuran básicamente siguiendo una serie de reglas y condiciones que en lenguaje informático se conocen como reglas del negocio. Estas reglas y condiciones se basan en la definición de cómo se debe comportar el sistema para tratar los datos que entran
a
ser
procesados.
Veamos
un
ejemplo,
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
20
supongamos que tienes un teléfono celular de prepago y debes cargarle dinero cada cierto tiempo para poder realizar llamadas. Analicemos el proceso de carga de dinero con un poco más de detalle ¿Qué datos de entrada necesitamos?, si dices que lo que necesitas es solamente el dinero que vas a cargar, es correcto, pero ¿eso es todo?, pensemos un poco más en detalle y pongámonos en algunos casos especiales, ¿es tu teléfono el único teléfono en el sistema?, claramente no por lo tanto es necesario identificar a qué teléfono quieres cargar el dinero, ahí aparece un nuevo dato que es el número de teléfono. Por lo tanto ahora ya tenemos los siguientes datos de entrada, el número de teléfono y el monto de dinero que vas a cargar. Ahora la pregunta es la siguiente, ¿que hace el sistema con los datos de entrada?, una respuesta acertada sería decir que suma al saldo anterior el valor que se está cargando, pero ¿a cual de todos los teléfonos que existen lo carga?, entonces ahí determinamos que primero hay que buscar la información asociada al teléfono y luego sumar el valor al saldo de dinero que tiene el teléfono. Así determinamos que el proceso se define en dos pasos: 1. Buscar los datos del teléfono usando el número. 2. Sumar el valor a cargar al saldo existente. Si te fijas ya estamos avanzando, pero ahora comienzan a surgir algunos inconvenientes, supongamos que buscas los datos del teléfono y te das cuenta que no es un teléfono de prepago sino que uno con plan, entonces ¿Qué haces?, si te fijas debes tomar un decisión usando UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
21
una regla, pensemos que hacer, ¿todos los teléfonos tienen el mismo plan?, la respuesta es no, de hecho existen
básicamente
tres
planes,
prepago,
cuenta
controlada y plan ilimitado, sólo a los dos primeros se les puede cargar dinero, pero bajo circunstancias distintas, al plan de cuenta controlada sólo le puedes cargar más dinero cuando se ha acabado el dinero anterior, mientras que al de prepago se le puede cargar en cualquier momento y si tienes plan ilimitado no le puedes cargar dinero. Con estos datos del proceso completo podemos definir que las condiciones son las siguientes: 1. Buscar los datos del teléfono usando el número. 2. Identificar si el teléfono tiene plan ilimitado. 3. Si lo tiene no se le puede cargar dinero. 4. Si no tiene plan ilimitado entonces hay que saber si el teléfono tiene plan de cuenta controlada. 5. Si tiene plan de cuenta controlada, debemos fijarnos en el saldo y ver si aún tiene. 6. Si tiene plan de cuenta controlada y tiene saldo no podemos cargar dinero. 7. Si tiene plan de cuenta controlada y no tiene saldo, entonces podemos cargar el dinero. 8. Si no tiene plan de cuenta controlada entonces sumamos inmediatamente el dinero al saldo anterior. Ahora sólo nos queda analizar cuál es la salida resultante de este proceso. Si analizamos con detención el objetivo del proceso es cargar dinero a tu teléfono celular, así podríamos definir dos posibles salidas, que son:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
22
a) Un mensaje que diga que el proceso se realizó de forma correcta o incorrecta. b) El nuevo saldo luego de realizada la carga. Analicemos el primer caso, si el proceso nos devuelve un mensaje
¿Podremos
conocer
el
nuevo
saldo?,
la
respuesta en este caso es no. Si devolvemos el nuevo saldo ¿Podemos saber si el proceso se realizó de forma correcta?, la respuesta en este caso es si, pero depende de un factor que es el conocer de antemano el saldo que tenía, así si al iniciar el proceso tenía 0 peso y luego de cargar 2000, tengo en mi saldo 2000 es que se realizó el proceso son éxito. Cabe destacar que ninguna de las soluciones es correcta y ninguna es incorrecta, pues ambas dependen de datos que faltan en la definición del contexto del problema.
Plantilla para prueba manual o seguimiento de ejecución de una secuencia lógica. Si bien la resolución de problemas simples como el planteado anteriormente pudiera parecer una tarea sencilla y libre de complejidades a veces es necesario corroborar si el proceso que hemos definido está correcto y podemos obtener el resultado deseado a través de lo que se conoce como una traza, es decir el seguimiento de los
valores
que
nos
interesa
controlar
y
el
comportamiento que vaya a tener el sistema en función de estos valores. UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
23
Para hacer la traza de un programa se van anotando los valores que nos interesa controlar y qué es lo que sucede cuando
esos
valores
cambian
asociándolos
a
las
decisiones que se realizan durante el proceso. Muchas veces se elabora una tabla para hacer la traza y registrar los valores de forma ordenada asociados a cada uno de los procesos y además se realiza una tabla para cada uno de los distintos cursos que pueda tomar la operación. Por ejemplo si hacemos la traza del ejemplo anterior de carga del teléfono podríamos dibujar la siguiente tabla: Datos de control Nro de Valor a cargar teléfono 84480965 3500
Acciones Buscar los datos del teléfono ¿El teléfono tiene plan ilimitado? Salida
Acciones Buscar los datos del teléfono ¿El teléfono tiene plan ilimitado? ¿Tiene cuenta controlada y su saldo es 0? Salida
Tipo Plan
Saldo
Ilimitado
0
Ilimitado
0 0
Datos de control Nro de Valor a cargar teléfono 84480965 3500
Acciones Buscar los datos del teléfono
Tipo Plan
Saldo
Cuenta Controlada Cuenta Controlada
0
Cuenta Controlada
3500
0
3500
Datos de control Nro de Valor a cargar teléfono 84480965 3500
Tipo Plan
Saldo
Prepago
1000
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
24 ¿El teléfono tiene plan ilimitado? ¿Tiene cuenta controlada y su saldo es 0? ¿Tiene cuenta controlada y su saldo es mayor a 0? ¿Es de prepago? Salida
Prepago
1000
Prepago
1000
Prepago
1000
Prepago 4500
Si te fijas en las tablas anteriores hay un conjunto de preguntas que generan una respuesta basándose en los valores proporcionados a la función. Para cada grupo de preguntas y respuestas se realiza alguna acción o acciones que llevan al resultado expresado en la salida.
Acciones Buscar los datos del teléfono ¿El teléfono tiene plan ilimitado? ¿Si tiene cuenta controlada su saldo es 0? Salida
Datos de control Nro de teléfono 84480965
Valor a cargar 3500
Tipo Plan Cuenta Controlada Cuenta Controlada Cuenta Controlada
Saldo 1000 1000 1000
1000
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
25
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
26
Técnicas de algoritmos para el diseño de procesos computacionales. Conceptos básicos. Algoritmo. La palabra algoritmo se deriva de la traducción al latín de la palabra árabe
alkhowarizmi ,
nombre de un matemático
y astrónomo árabe que escribió un tratado sobre manipulación de números y ecuaciones en el siglo IX.
Un algoritmo es una serie de pasos organizados que describe el proceso que se debe seguir para dar solución a un problema específico.
Otra definición más específica es: Conjunto de pasos finitos no ambiguos que permitan dar solución a un problema específico. A simple vista la definición formal de algoritmo puede no ser tan clara por si sola, pero verás que un algoritmo es algo que ya conoces y lo mejor es que durante toda tu vida has ejecutado varios algoritmos sin darte cuenta, comencemos con un ejemplo básico, ¿has jugado alguna vez a encontrar el tesoro pirata siguiendo un mapa? Aquel papelito de color café que dando un par de pasos en varias direcciones te lleva a un lugar que marca una X, pues aquel papel lo que tiene escrito dentro en realidad es un algoritmo. veamos por qué: primero el UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
27
papel nos señala el lugar de inicio, luego de ello las instrucciones que sigues dicen algo así como “dos pasos a la derecha”, “un paso a la izquierda”, este tipo de instrucciones son un conjunto de pasos finitos, dado que no son interminables, tiene un punto de comienzo (donde obliga a ubicarte) y un final (donde marca la X), tampoco son ambiguos por que no hay doble interpretación para cada una de ellas, finalmente si sigues todas las instrucciones en orden encontrarás el lugar donde esta la X, entonces también podemos aseverar que estos pasos sirven para resolver un problema especifico, el cual nos indica el camino desde un punto hasta otro, donde debajo de la gran X probablemente nos esperen algunas monedas de oro. Sin embargo y siguiendo este criterio muchas actividades van a comenzar a parecer un algoritmo y de hecho es muy probable que lo sean, sin embargo no todo es un algoritmo y es bueno que también sepamos reconocer lo que no lo es, supongamos que estas viendo un programa de televisión donde están dictando una receta para cocinar un rico pastel bañado en chocolate, esta receta será entonces un algoritmo si los pasos de la preparación especifican los factores de tiempo y material que se deben utilizar en cada uno de ellos, si en determinado momento entre el listado de actividades que hay que realizar existe alguno que diga algo así como “agregue azúcar a gusto” el gusto” el conjunto de instrucciones dejará de ser un algoritmo, debido a que existe un paso ambiguo.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
28
En informática el algoritmo es una de las piezas fundamentales en el desarrollo de software ya que el computador
responderá
a
algoritmos
que
nosotros
diseñemos y pediremos a él que ejecute, para ello lo haremos a través de los lenguajes que el computador entiende,
los
cuales
irás
aprendiendo
durante
el
desarrollo de tu carrera. Todo lo que ejecuta el computador son algoritmos, un buen diseño de un algoritmo hace mejor y más rápido a un programa, ¿cómo
la
¿te has detenido alguna vez a pensar calculadora
resuelve
las
operaciones
encomendadas?, es probable que no, pero de lo que sí podemos estar seguros es que la calculadora es una gran ejecutora de algoritmos, ya que cada calculo matemático es resuelto mediante algoritmos, es decir pasos que ya están definidos para resolver una operación, de ellos podemos destacar el cálculo del potencial, el cual es un algoritmo muy popular, que da solución a cálculos como por ejemplo 24 =16. Otro algoritmo famoso es el de Dijkstra, este algoritmo es el encargado de encontrar la ruta más corta entre dos puntos, es muy posible que lo hayas visto sin saberlo en los video juegos, ya que este algoritmo es el encargado de hacer que tus tropas avancen desde un punto hacia otro buscando el mejor camino en muchos juegos de estrategia Hacer buenos algoritmos no es una tarea sencilla, requiere de práctica y mucha lógica, durante este manual vas aprender a desarrollar tu lógica y comprender qué partes componen el problema que deseas solucionar, UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
29
cuáles son los datos de entrada y cuál es el conjunto de pasos que debes aplicar sobre los datos para generar el resultado
deseado,
el
cuál
no
es
otra
cosa
que
información para la persona que lo solicita, también aprenderás a cómo optimizar los algoritmos, para que tengas una idea, la optimización corresponde a la capacidad de lograr reducir la cantidad de pasos para solucionar
el
mismo
problema,
una
de
las
cosas
interesantes que tienen los algoritmos es que existe muchas formas de solucionar un mismo problema, con el tiempo te darás cuenta que incluso habrán ocasiones en las que para un ejercicio dado todos tu compañeros tendrán eventualmente una solución distinta. Tipos de Algoritmos Cualitativos: Son aquellos en los que se describen los pasos utilizando palabras. Cuantitativos: Son aquellos en los que se utilizan cálculos numéricos para definir los pasos del proceso. Lenguajes Algorítmicos. Es una serie de símbolos y reglas que se utilizan para describir de manera explícita un proceso. Hay dos tipos: Gráficos: Es la representación gráfica de las operaciones que realiza un algoritmo. Ejemplo: Diagrama De Flujo, DFD. No
Gráficos:
Representa
en
forma
descriptiva
las
operaciones que debe realizar un algoritmo. Ejemplo: Pseudocódigo. UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
30
Características de un buen algoritmo.
Debe tener un punto único de inicio.
Debe
ser
definido,
no
debe
permitir
dobles
interpretaciones.
Debe ser general, es decir, soportar la mayoría de las
variantes que se puedan presentar en la definición del problema.
Debe ser finito en tamaño y tiempo de ejecución. Es
decir, debe tener un fin.
Diagrama de flujo Para el diseño de algoritmos se utilizan técnicas de representación. Una de estas técnicas son los Diagramas de Flujo (DDF), que se definen como la representación gráfica que mediante el uso de símbolos estándar unidos mediante líneas de flujo, muestran la secuencia lógica de las
operaciones
o
acciones
que
debe
realizar
un
computador, así como la corriente o flujo de datos en la resolución de problema.
Pseudocódigo. El escribir aplicaciones computacionales se necesita entregar al computador una serie de instrucciones las cuales serán ejecutadas por este. Para realizar este proceso se inventaron los lenguajes de programación mediante
los
cuales
el
programador
escribe
las
instrucciones para que el computador realice las acciones correspondientes,
el
programador
escribe
estas
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
31
instrucciones
las
cuales
son
interpretadas
y
luego
compiladas (transformadas en un lenguaje que entiende el computador llamado lenguaje de máquina), para que con el resultado de este proceso pueda ejecutar las instrucciones. Ahora como los lenguajes de programación a veces son muy complejos de aprender, existe un subconjunto de lenguajes más básicos que se llaman pseudolenguajes, los
cuales
permiten
generar
pseudocódigo.
El
pseudolenguaje generalmente es un subconjunto de un lenguaje de programación que es muy extenso, o a veces también se trata de un lenguaje que ocupa expresiones que son más cercanas al lenguaje de las personas, pues en todos los lenguajes de programación las instrucciones están en inglés. Si bien existe una cercanía mayor con el lenguaje con el que hablas (en este caso español), existe la complejidad posterior de tener que aprender de nuevo otro lenguaje de programación. Para efectos de este manual,
ocuparemos
un
lenguaje
de
programación
llamado java el cual tiene una sintaxis relativamente simple. Adicionalmente la sintaxis de java esta basada en un lenguaje de programación denominado C que es el padre de los lenguajes más utilizados: C++, javascript, java,
c#, actionscript, php, entre otros, que utilizarás
durante el desarrollo de tu carrera.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
32
Programa. Conjunto
de
órdenes
o
instrucciones
capaces
de
manipular un conjunto de de datos. datos. Estas órdenes pueden ser
divididas
en
tres
grandes
bloques
claramente
diferenciables, estos son:
• Entrada de datos: En este bloque se engloban todas aquellas instrucciones que toman datos de un dispositivo o periférico externo, depositándolos en la memoria principal del computador para ser procesados.
•
Proceso:
Engloban
todas
aquellas
instrucciones
encargadas de modificar los datos que previamente habían sido depositados en la memoria principal. Todos los resultados obtenidos en el tratamiento de dichos datos son depositados nuevamente en la memoria principal quedando de esta manera disponible.
• Salida de resultados: Es el conjunto de instrucciones que toman los resultados finales desde la memoria principal y lo envían a dispositivos externos.
Etapas en la creación de programas. Durante el desarrollo hay un conjunto de etapas que sin importar el tipo de software que desee crearse siempre se repiten, ya sea desde un programa muy simple como una calculadora con las operaciones básicas, hasta completos sistemas de cálculos en tiempo real. Estas UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
33
etapas serán definidas y explicadas en forma lineal, sin embargo en el desarrollo real no significa que este sea un orden estricto y que no haya vuelta atrás, muy por el contrario, en muchas ocasiones cuando ya se piensa que se ha superado por completo una etapa es necesario volver atrás, agregar o corregir algo que se nos pasó para luego volver a la etapa siguiente. Otra cosa importante, es que en algunas ocasiones también se da que las etapas se solapan, vale decir, que antes de finalizar una es posible avanzar en algunos puntos de la que
viene,
esto
suele
ser
útil
para
comenzar
a
dimensionar si lo que estamos haciendo esta correcto.
Requisitos. Los requisitos de software son especificaciones claras y puntuales sobre lo que debe contener un software para cumplir con algún requerimiento. Es habitual que las personas confundan requisito con requerimiento, incluso una discusión de ello se encuentra en el manual de análisis y diseño orientado a objetos dentro del capitulo de ingeniería de requerimientos, pues bien, en ese capítulo se habla de la necesidad de extraer la información sobre los procesos que realizan los clientes los cuales luego queremos construir como software más adelante, dichas necesidades son requerimientos y están asociados a las necesidades que tiene la empresa y que luego resolveremos o apoyaremos con un software, un requisito en cambio está más bien asociado a lo que debe UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
34
hacer un software para que en su funcionamiento cumpla con lo que deseamos construir, veámoslo con un ejemplo: si deseas construir un software para apoyar el proceso de venta de juguetes, estamos hablando de un requerimiento,
sin
embargo,
cuando
dices
que
tu
software necesita validar que el método de pago sea sólo en pesos chilenos, entonces estamos hablando de un requisito del software, los cuales en su conjunto debiesen alinearse con los requerimientos. Una forma fácil de recordar la diferencia es mirar la contratapa de algún software que hayas comprado alguna vez, allí veras los requisitos mínimos necesarios para se ejecución y que por tanto están absolutamente ligado a una pre condición del software, no del proceso que desea resolver.
Análisis. En la etapa de análisis es en la que recopilamos todos los requisitos necesarios para desarrollar el software, los analizamos y buscamos restricciones que deban ser aplicadas por el software. Este análisis es recomendable hacerlo en equipo, para ello los encargados cuentan con un conjunto de diagramas que les permiten dibujar los procesos que desean construir antes de comenzar a desarrollar la aplicación. Esta etapa es fundamental en el ciclo de desarrollo de un software, un mal análisis de los requisitos podría tirar por la borda el esfuerzo de mucho tiempo. UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
35
Diseño de la solución. En el diseño de la solución es el momento en el que se planifica la arquitectura de lo que se desea construir, el diseño de una aplicación abarca varios temas, algunos mucho más complejos que otros, donde todo dependerá del tipo de aplicación que deseamos construir. Durante esta asignatura el diseño que abarcaremos estará principalmente enfocado a cómo organizaremos el código dentro de una sola aplicación, tal vez por ahora sea complicado de comprender, pero pequeñas rutinas de código con el tiempo las iremos organizando y agrupando en
métodos,
donde
cada
uno
de
estos
métodos
representa un proceso, es decir una entrada de datos, algún conjunto de operaciones aritméticos y lógicos que aplicaremos sobre ellos, para luego generar una salida. En la medida que vayamos aprendiendo resolveremos ejercicios más complejos donde para llegar a una solución necesitaremos
crear
varios
procesos,
los
cuales
agruparemos en una entidad mayor llamada clase, dichas clases y sus métodos (o comportamientos) dibujaremos en un diagrama llamado “diagrama de clases” . El diseño no sólo se refiere a cómo organizaremos los componentes internos de un programa, hay ocasiones en que una solución consta de más de un programa, por ejemplo, hay redes sociales que tienen un componente Web y otro en equipos móviles, en este caso el diseño
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
36
también debe incorporar la forma en que ambos software se comunicarán. Otro aspecto que también se refiere al diseño, es la forma en que los componentes se instalarán. Muchas veces los software están diseñados para recibir grandes cargas de datos o altos niveles de tráfico de usuarios y están ejecutándose sobre más de un equipo, por lo que en estas ocasiones, el diseño también esta ligado al hardware en el que se ejecutará. Conocer esto a tiempo, nos dará una pauta de la forma lógica en la que debemos construirlo.
Codificación. Esta etapa se refiere a la construcción del software, es el equivalente a comenzar a levantar los cimientos de una casa luego de que ha sido diseñada. La codificación es un proceso que no debiese generar problemas si el análisis de requisitos ha sido realizado correctamente y si los programadores están guiándose por un diseño (diagrama de clases) que ha sido discutido y aprobado por el equipo responsable. Durante esta etapa los programadores deberán idear los algoritmos que permitan solucionar cada uno de los objetivos planteados en el diseño de la solución y la comunicación entre las partes. Durante la codificación utilizaremos algún lenguaje de programación que nos permita comunicarnos con la UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
37
máquina, la elección del lenguaje es una conversación que da para mucho, pero por lo general depende de las prestaciones que nos da la tecnología que la rodea, de las restricciones y aunque no debiese ser una limitante, muchas veces influye su valor.
Prueba. Las
pruebas
corresponden
a
la
etapa
de
la
post
construcción, aquí es donde probamos lo que hemos construido. Para iniciar las pruebas no es necesario terminar el software completo, los programadores suelen hacer
muchas
pruebas
de
cada
método
que
han
construido con el fin de determinar si sus algoritmos hacen lo que se espera de ellos. A estas pruebas se les llama prueba unitaria y consiste básicamente en ingresar datos de entrada y verificar que la salida sea la esperada, además suelen hacerse durante todo el periodo de codificación. Adicionalmente, existen otros tipos de pruebas que tienen relación con la cantidad de recursos que un software utiliza, esta tarea por lo general realizada por el departamento de “aseguramiento de la calidad” realiza tareas como la revisión de la carga del procesador y los tiempos de respuesta de la aplicación.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
38
Mantención. La mantención del software es un proceso que se realiza post entrega y corresponde a modificaciones posteriores. Las mantenciones siempre nacen a causa del cambio de un proceso en la organización del cliente que lo ha solicitado. Las mantenciones pueden ser una buena fuente de ingreso posterior a la venta, ya que casi siempre las mantenciones son realizadas por la misma empresa desarrolladora, sin embargo en otras pueden convertirse en un gran dolor de cabeza cuando el software ha sido construido de forma poco modular (divididos en sub programas), la mantención se vuelve muy dificultosa y los cambios en una parte comienzan a provocar errores en otros. Algunos paradigmas de programación como la programación orientada a objetos (POO) aporta mucho a la facilidad de mantener sistemas, ya que divide los procesos en procesos más pequeños y luego los agrupa con un nombre que los represente, de esta forma es más sencillo ubicar donde hay que realizar el cambio y cuales son los datos de entrada y salida esperados.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
39
Características de la Características programación. Estructura descendente. En la etapa de análisis se determina que hace el programa, en la etapa de diseño se determina cómo hace el programa la tarea solicitada. Con el objetivo de hacer el proceso de la resolución de problemas más eficaz es que se utiliza el proceso de diseño conocido como “divide y vencerás”. Esto quiere decir que la resolución de problemas
complejos
se
realizan
dividiendo
dicho
problema en subproblemas y a continuación dividir dichos subproblemas en otros de nivel más bajo hasta que pueda ser implementada la solución. La solución de estos subproblemas
se
realiza
con
subalgoritmos.
Los
subalgoritmos son unidades de programa o módulos que están diseñados para ejecutar alguna tarea específica. Estas unidades (las que distinguiremos como “Funciones” y “Procedimientos” y que estudiaremos en profundidad más adelante) se escriben sólo una vez, pero pueden ser invocadas o referenciadas en diferentes puntos del programa o “módulo principal” con el objeto de no duplicar el código innecesariamente. Este método de diseñar algoritmos con el proceso de “romper” el problema subdividiéndolo en varios subproblemas se denomina
“diseño
descendente”,
“TOP-DOWN” “TOP-
o
“Modular” y en cada etapa, expresar cada paso en forma más detallada se denomina “refinamiento sucesivo” . Cada subprograma es resuelto en un módulo que tiene UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
40
un único punto de entrada y un solo punto de salida. Los módulos pueden ser planeados, codificados, comprobados y
depurados
de
forma
individual
(hasta
por
programadores distintos) y combinarlos mas tarde lo que implica la combinación de los siguientes pasos:
Programar un módulo.
Comprobar el módulo.
Depurar el módulo
Combinar el módulo con los demás.
Esta técnica es utilizada hoy en casi todas las disciplinas, en programación existe más de un paradigma (una forma o modelo modelo de cómo hacer las las cosas).
Modularidad. El concepto de modularidad en programación esta directamente
asociado
al
divide
y
vencerás.
Este
concepto hoy está fuertemente asociado al paradigma de programación orientado a objetos, el cual tiene como principio dividir la funcionalidad de un programa en programas más pequeños de manera en que ellos sean lo más independientes posible.
Cohesión. Este término tiene relación con la capacidad de unir las partes, la palabra cohesión es sinónimo de adhesión, por lo tanto estamos hablando de la unión de partes. En la UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
41
programación siempre se busca hacer todo modular, es decir tomar un gran software y construirlo de pequeñas partes
que
ojalá
fuesen
funcionales
de
forma
independiente, sin embargo si vamos a programar de esa manera hay que pensar después en como unir todo, a este concepto se le llama cohesión y se dice que un software tiene una alta cohesión cuando la llamada a una de esas partes la realiza una que contiene toda la información para ello.
Acoplamiento. El acoplamiento esta muy ligado a la cohesión, cuando un software se encuentra dividido en partes y estas partes son unidas de forma correcta estamos hablando de una alta cohesión entre las partes, cuando esto esta presente en un software de forma automática decimos entonces que
nuestro
programa
tiene
un
bajo
nivel
de
acoplamiento, lo que es muy bueno, ya que esto quiere decir que las partes no son dependientes entre sí, por tanto, una modificación en un proceso sólo afectará a alguna de las piezas del software y no al 100%, evitando volver a modificar partes que si funcionan y cuya función no se ve alterada.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
42
Descomposición. La descomposición es una característica que permite “desarmar” un problema complejo en una serie de subproblemas que por el hecho de ser partes reducidas de un todo, pierden complejidad. Esta pérdida de complejidad nos permite concentrarnos en una parte específica del del problema utilizando el concepto de “divide y vencerás”.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
43
Estructura de un algoritmo algoritmo.. Los algoritmos se definen como una serie de pasos bien definidos y finitos que permiten solucionar solucio nar un problema para cualquier tipo de valores. Básicamente un algoritmo permite definir las acciones que se deben realizar para solucionar un problema. Existe una serie de acciones que acciones que se realizan para dar solución a un problema, por ejemplo declarar variables, leer datos desde teclado, mostrar datos en una pantalla, etc. Esta serie de acciones se ordenan lógicamente para solucionar un problema. Un ejemplo de la definición de la estructura de un algoritmo es el siguiente: 1. 2. 3. 4. 5.
Leer el pedido. Examinar el historial de crédito del cliente. Si el cliente es solvente, entregar el pedido. ped ido. En caso contrario, rechazarlo. Fin.
Si te fijas en el ejemplo anterior, existe una serie de pasos formales para dar solución a un problema que en el caso anterior es tomar una decisión respecto a si se entrega o no un pedido a un cliente utilizando el historial de crédito que posee.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
44
Conceptos de variables y constantes. Definición de variables y constantes. Cuando creamos software, los datos que van a ser procesados, se deben guardar de forma forma
temporal para
ser procesados por la aplicación. El programa por lo tanto debe solicitar al sistema operativo que defina un espacio en la memoria donde guardar estos datos. Para esto los lenguajes
de
programación
definen
una
forma
de
reservar este espacio y es mediante la declaración de variables y constantes. Cuando se declara una variable o una constante, se realiza el proceso de solicitar un espacio en la memoria del computador para almacenar valores que representan datos que queremos procesar. El problema surge cuando nos damos cuenta que el espacio en la memoria del computador es limitado, por lo tanto el sistema operativo para proteger la ejecución de múltiples programas
nos
solicita
que
pidamos
un
espacio
específico, en función de lo que vamos a guardar, por ejemplo si tengo que construir un lugar para guardar mi auto, no construyo un galpón para guardar un avión, porque lo más probable es que no ocupe todo el espacio y quede con mucho espacio sin utilizar, de la misma forma que no construyo un galpón para guardar una moto, pues lo que necesito guardar es un auto. Por lo tanto para indicar al sistema operativo cual es el espacio
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
45
que se debe dejar disponible para guardar datos, los lenguajes de programación definen los tipos de datos. da tos. Un tipo de dato por lo tanto permite definir el espacio en la memoria que el sistema operativo reservará para guardar datos que serán procesados por un software. En
java
los
tipos
de
datos
se
pueden
catalogar
básicamente en dos grupos, los primitivos (o simples) y las referencias a objetos.
Primitivos Los tipos de datos primitivos son aquellos que pueden utilizarse directamente en un programa sin necesidad de utilizar POO, dado que no son objetos, los tipos de datos primitivos
aportan
un
uso
más
eficiente
en
el
almacenamiento de datos y pueden ser divididos en dos grupos,
los
booleanos
y
numéricos,
los
cuales
se
subdividen en dos grupos, los enteros (byte, short, int, long y char) y los reales (float y double).
(Importante) la declaración de una variable utiliza la siguiente sintaxis: Tipo de dato identificador = [valor][, identificador] [=valor]… ;
En java los identificadores también tienen una norma. La forma correcta de declarar una variable es escribiéndola con minúsculas y las mayúsculas sólo se utilizan en la primera letra a partir de la segunda palabra si es que la hay, por ejemplo el identificador “miVariable” lleva la letra “V” con mayúscula debido a que es una palabra UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
46
escrita
después
de
“mi”
lo
mismo
sucede
con
“miPrimeraVariable”, donde tanto P como V van con mayúsculas
byte: El byte es una variable que tiene una capacidad de 8 bits y permite almacenar un valor de tipo entero (sin decimales) entre el -128 y + 127. El siguiente ejemplo declara la variable y luego le asigna el valor de cero, cuando un valor es dado de forma inicial recibe el nombre de inicialización de la variable. byte dia=0;
(Importante) las variables pueden ser inicializadas con un valor (cero en este caso) o una expresión. Se entiende por expresión un conjunto de operadores que dan un resultado, pudiendo así declarar byte (o cualquier otro tipo de dato) de la siguiente forma:
byte a = 1+1*2; también debes tener en cuenta que las variables numéricas no inicializadas comienzan en cero.
Short: El short tiene una capacidad de 16 bits y permite almacenar un valor entero entre -32768 y +32767 (al igual que el entero en C). La siguiente línea de código declara e inicializa dos variables.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
47
Int: El tipo de dato entero tiene una capacidad de 32 bits y permite almacenar un valor entero entre -2147483648 y +2147483647.
Long: El tipo de dato long tiene una capacidad de 64 bits y permite
almacenar
un
valor
entero
entre
9.223.372.036.854.775.808
y
+9.223.372.036.854.775.809
Float: El tipo de dato float tiene una capacidad de 32 bits y permite almacenar un valor real en coma flotante (decimales) entre -3,4*10-38 hasta 3,4*1038 . Los valores expresados en float deben ir acompañados de una letra f minúscula al final.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
48
Double: El tipo double tiene una capacidad de 64 bits y permite almacenar un valor real entre -1,7*10-308 y +1,7*10308. El double es el tipo de dato que asume Java al escribir un real, por ello no va acompañado de ningún carácter como en el caso del float.
Boolean: El tipo de dato booleano es utilizado para conocer el resultado de una evaluación booleana, los dos posibles valores son true y false (verdadero y falso).
Si su valor de inicio no es especificado, el valor por defecto es false.
Char: El tipo char, es un tipo de datos que permite almacenar un caracter, sin embargo el valor que en realidad almacena es un entero equivalente entre los valores del 0 al 127 de la tabla de caracteres ASCII, la forma de declarar un char es la siguiente:
(Importante) Para el caso de la variable letra1 el valor es el caracter a, el cual sebe ir entre comillas, sin embargo en letra2, las comillas no existen, porque no se le está asignando un carácter, el número 97 representa la letra a UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
49
en la tabla ASCII, esto significa que la variable letra1 y letra2 tienen en realidad la misma letra almacenada.
Tipo de objetos. Los tipos de objetos incluyen todos los objetos que pueden
ser
instanciados
a
partir
de
las
clases
provenientes con java y todas las que sean desarrolladas por el programador. Si bien ambos tópicos serán vistos más adelante, en este capítulo se mostrará el String, la cual es una clase de mucha utilidad y que a veces tratada como un tipo primitivo, aunque no lo sea.
String Un String (con su letra “s” mayúscula) no es un tipo de dato primitivo, sin embargo se trata en este apartado debido a que su uso es muy habitual en los programas y adicionalmente se puede utilizar de la misma forma en la que se declaran los tipos primitivos. Un String es un tipo de
dato
que
permite
almacenar
una
cantidad
de
caracteres variables. Su declaración y asignación es de la siguiente forma:
(Importante) String, es en realidad una clase, que almacena como atributo un arreglo de caracteres. Tanto las clases como los arreglos serán estudiados con mayor detalle más adelante. El siguiente ejemplo muestra la
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
50
declaración
de
variables
bajo
el
paradigma
de
la
programación estructurada dentro del método main.
La
siguiente
imagen,
presenta
un
ejemplo
de
la
utilización de los tipos vistos en declaración de atributos de nuestra clase Persona.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
51
(Importante) private representa el nivel de accesibilidad y será estudiado más adelante.
Vida y ámbito de una variable Las variables cuando son declaradas, tienen lo que se conoce como un ámbito, el cual define las fronteras dentro de las cuales las variables pueden ser utilizadas. Tradicionalmente la programación estructurada estructurada tiene dos niveles de visibilidad distintos: las variables locales y globales, sin embargo en la programación orientada el ámbito de una variable dentro de una clase es algo más UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
52
complejo y será tratado a lo largo de este manual. Las variables siempre deben ir dentro de una estructura que los contenga, para cada estructura existe un inicio y cierre de bloque que la delimita. Como ejemplo la siguiente imagen muestra una clase con su respectivo inicio y cierre de bloque.
Fíjate que ahora la clase Persona posee además un comportamiento llamado correr y descansar, los cuales también
tienen
limitado
su
bloque.
Podemos
decir
entonces que la clase Persona contiene dentro un comportamiento llamado correr y descansar.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
53
En este caso, la variable cansancio es una variable de instancia debido a que está definida dentro de la clase, pero fuera de sus comportamientos, por ende los métodos descansar y correr (que también son parte de la clase) tienen visibilidad sobre cansancio, aumentando en este caso su valor al correr y disminuyéndola al descansar.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
54
El ámbito de una variable siempre dependerá de del lugar donde se produzca su declaración, por ejemplo, ya vimos que si declaramos la variable dentro de los bloques que limitan
la
clase
persona,
pero
fuera
de
correr
o
descansar, la variable se denomina una variable de instancia y está disponible para todos los métodos que la clase contenga. En el siguiente ejemplo la variable cansancio es ahora una variable declarada dentro de del comportamiento correr, esto se denomina variable local del método. método. Para este caso la visibilidad de dicha variable son los límites donde fue declarada, vale decir el inicio y bloque de correr, el siguiente ejemplo causa un
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
55
error debido a que descansar no tiene una visibilidad sobre la variable cansancio.
(Importante) las variables de instancia son capaces de mantener el valor durante toda la vida de un objeto, sin embargo las declaradas dentro de un comportamiento son creadas, utilizadas y eliminadas al finalizar la ejecución del comportamiento que la contiene. También es posible crear límites dentro de los comportamientos correr, si bien la técnica que se presenta en el siguiente no es muy común, es reconocida por el lenguaje Java.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
56
En el segmento de código anterior se muestran dos casos a considerar. En el interior del método correr existe una delimitación dentro que contiene la declaración de una variable entera cuyo identificador es “a”, sin embargo al
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
57
terminar el límite donde fue declarada la variable ha vuelto a ser declarada, a primera vista da la idea de que correr tiene dos variables llamadas “a”, pero pe ro sabemos que eso es imposible. Recordemos que el identificador de una variable debe ser único en un mismo ámbito, lo que en realidad sucede es que la variable que se declara primero tiene una vida útil desde que se declara hasta el cierre de bloque en el que fue declarada, por ende al ser declarada la segunda variable llamada “a”, la primera ya ha sido eliminada. En descansar en cambio se produce un error debido a que se declara primero una variable entera dentro de los límites del comportamiento descansar, lo que provoca que también esté disponible para el ámbito que existe en el interior del método, por lo tanto, en el ámbito interior, no es posible declarar la variable entera con el identificador “a”, debido a que ya existe en él.
Conversión entre tipos. En Java existen dos tipos de conversiones, la implícita y explicita. La implícita es aquella que no necesita de alguna intervención por parte del programador para que se lleve a cabo, siendo Java el encargado de realizarla. El ejemplo más común es la operación aritmética de dos tipos de datos distintos, ¿en una variable de qué tipo debo almacenar el resultado entre la suma entre un float y un double?
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
58
La clave a la respuesta de esta pregunta no está en el resultado de la operación, de hecho, en este caso el resultado es 6, el cual podríamos asumir de forma errónea que es un resultado entero, sin embargo la clave del éxito está en el tamaño del resultado. Si tuvieses que construir un estacionamiento, donde se estaciona un camión gigante o un pequeño auto, pero nunca los dos al mismo tiempo, ¿cuál es el estacionamiento más pequeño que debes construir? El del tamaño del camión, pues Java hace lo mismo, el double es un valor más grande (en bits) que el float, por ende Java siempre dará como resultado el tipo más grande, con ello se asegura de que no exista perdida de precisión en el resultado.
La conversión implícita es aplicada en la dirección de izquierda a derecha entre los datos presentados en el siguiente diagrama, lo que significa que un byte, puede almacenarse en una variable de tipo short o char o cualquiera de las 3 puede almacenarse en un int.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
59
La conversión explícita o también conocida como cast consiste en forzar la conversión entre un tipo de dato a cualquier otro (excepto desde booleanos a enteros o reales), la sintaxis para realizar una conversión explicita es la siguiente:
(Tipo destino) expresión o variable
A=(int)promedio;
En el siguiente ejemplo, se convierte una expresión que da como resultado un float (debido a que es más grande que un short y un long) en un entero, dando como resultado el valor de 3.
(importante) muchas veces se piensa que el resultado es 4, debido a que la suma de las tres variables da en realidad 3.8f sin embargo convertir este resultado a un entero no implica una aproximación, sino que sólo tomar la parte entera del valor resultante (también conocido como truncar datos) El siguiente ejemplo muestra una clase en la que el comportamiento miPeso el cual retorna los kilos de su peso sin contar los gramos.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
60
Representación de sentencias en Instrucciones. Operadores Aritméticos. Los operadores aritméticos son aquellos que permiten realizar operaciones matemáticas y son:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
61
El siguiente ejemplo muestra una operatoria aritmética que incluye una conversión explicita cuyo resultado es 4:
Operadores unarios y de auto asignación
Este tipo de operadores son una forma reducida de utilizar los operadores aritméticos tradicionales, por ejemplo: Dada la declaración int a=6; la siguiente tabla muestra las equivalencias:
Debes
prestar
especial
atención
cuando
uses
los
operadores -- y ++ dentro de una expresión aritmética, UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
62
debido a que el orden en el que se utilizan cambia el resultado de la operación. -- y ++ pueden ser utilizados como sufijos o como prefijos, lo que implica la jerarquía con la que se ejecuta, por ejemplo, en este caso ++ está antes de la variable “a” lo que implica que previo a cualquier operación que vaya ejecutarse sobre él la prioridad es incrementarlo en 1, siendo el resultado para este caso igual a 6 dado que a es 1 antes de ejecutar la suma.
Operadores Lógicos Relacionales Se usan para formar expresiones booleanas, es decir expresiones que al ser evaluadas producen un valor booleano: verdadero o falso. Se utilizan para establecer una relación entre dos
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
63
Cuando la comparación se hace con datos alfanuméricos, opera de acuerdo a las siguientes reglas:
Se compara uno a uno de izquierda a derecha. d erecha.
Si son de diferente longitud pero exactamente iguales
hasta el último carácter del más corto, entonces el más corto es el menor.
Sólo son iguales dos datos alfanuméricos si son
iguales su contenido y su longitud.
Las letras minúsculas tienen mayor valor que las
mayúsculas. (tabla ascii)
Booleanos: Combinan sus operandos de acuerdo al álgebra de Boole para producir un nuevo valor que se convierte en el valor de la expresión.
OR u O: O: es un operador binario, afecta a dos operadores. La expresión que forma es verdadera cuando al menos uno de sus operandos es verdadero. Es un operador de disyunción. Ejemplo: estudiamos o vamos al estadio AND o Y: Y: también es un operador binario. La expresión formada es cierta cuando ambos operadores son ciertos al mismo tiempo. Es el operador lógico de conjunción Ejemplo: si es verano y hace calor vamos a la playa NOT o NO: NO: es un operador unario, afecta a un solo operando. Cambia el estado lógico de la expresión; si es UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
64
verdadera la transforma en falsa y al revés. Ejemplo: no es verano. El orden de prioridad de estos operadores es: NOT, AND y OR .
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
65
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
66
Introducción a lenguajes formales de Programación. Estructura de un programa. En JAVA al igual que en la mayoría de los lenguajes de programación orientados a objetos, el código se estructura en clases, la forma básica de estructurar una clase es la siguiente: · Los Atributos que representarán un objeto, por ejemplo, para una persona los atributos pueden ser, su edad y peso entre otros, los atributos de una clase están representados por la declaración de estructuras y tipo primitivos, para este caso por ejemplo, la edad puede estar representada por un tipo de dato int (entero) y un float respetivamente. · Accesadores y mutadores, los cuales son comportamientos especiales dentro de una clase que permiten conocer y cambiar el valor de un atributo. · Los comportamientos que un objeto tendrá, por ejemplo, para nuestra persona, algunos ejemplos son correr y jugar.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
67
Sentencia condicionales Las sentencias condicionales representan un punto en nuestro programa donde el flujo del proceso cambiará dependiendo de alguna condición. Si haces un análisis simple
verás
que
esto
no
es
tan
complicado
de
comprender como se lee, la vida a diario esta lleno de condiciones, las cuales vamos resolviendo día a día y esto provoca que nuestro diario vivir sea incierto, siempre hay una condición para todo, por ejemplo, dependiendo si vas o no atrasado decidirás si ir a estudiar en metro o bus, dependiendo de qué día es, la hora a la que te levantarás. Este proceso mental es tan rápido que apenas nos habíamos dado cuenta que lo realizamos tantas veces al día. Si a cada una de estas situaciones que nos enfrentamos a diario nos detuviéramos un momento y nos analizáramos de qué depende que vayamos hacer algo, nos daríamos cuenta que programar es muy similar, por ejemplo, imagina que alguien te ofrece bebida y antes responder en voz alta expresas la condición que te llevará a determinar si aceptas o no, si lo haces muy probablemente dirás algo similar a “¿tengo sed?” y si la respuesta es verdadera entonces lo harás. Una condición esta antecedida de la conjunción si (sin acento). Podemos hacer uso de ella entonces para formular
todas
aquellas
condiciones
a
la
que
enfrentamos a diario, algunos ejemplos son: Si mi amigo va, yo voy. Si estoy aburrido jugaré PC. UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
nos
68
Si me han enseñado algo nuevo lo reforzaré. Fíjate que en cada una de las frases anteriores hay una acción que va a realizarse dependiendo de la condición expresada en el sí, además debes notar que si bien no esta escrito explícitamente también estamos diciendo que si la condición no se cumple hay algo que dejaré de hacer. En informática este comportamiento es exactamente igual, salvo por la forma en la que se escribe. Recuerda que para comunicarnos con el computador debemos usar algún lenguaje de programación y los lenguajes que más se utilizan en el mercado están en inglés, así que comenzaremos a dar nuestro primer gran paso en el mundo de las condiciones, cambiaremos la conjunción si, por la palabra clave if. if mi if mi amigo va, yo voy. if estoy if estoy aburrido jugaré PC. if me if me han enseñado algo nuevo lo reforzaré. Bien, ya nos vamos acercando a nuestra meta y de lo anterior podemos afirmar entonces que la palabra if debe siempre ir acompañada de una condición la cual también debemos representar de una forma que el computador pueda entender. Supongamos ahora que para ir de paseo con tus amistades hoy necesitas cancelar una cuota de $10.000, en ese caso la condición debemos expresarla de la siguiente forma:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
69
if (plata >= 10000) Donde plata es una variable que contiene algún valor el cual podrá ser mayor, menor o igual a $10.000, no importa el valor que esta tenga , siempre una sentencia condicional de este tipo tendrá dos posibles resultados, en
el primer caso
se cumple la condición
y en el
segundo la condición no se cumple .El resultado de la condición siempre determina si hay o no hay que hacer algo, en este caso por ejemplo si el valor de la variable plata es mayor o igual 10.000, entonces saldremos de paseo, de lo contrario podemos tomar dos acciones posibles, no hacer nada o buscar una actividad donde no necesitemos esa cifra de dinero. Adicionalmente tal y como lo muestra el ejemplo la condición debe ir entre paréntesis. Supongamos ahora que si la condición se cumple entonces podremos salir de paseo lo que provoca un incremento de uno en la variable diversión, en este caso el if será if será presentado de la siguiente forma:
if(plata >= 10000) { diversion++; } Como puedes ver justo debajo de la condición el incremento de la variable diversion se encuentra entre un inicio de bloque bloque “{“ y un cierre de bloque “}”. Estos UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
70
bloques delimitan el alcance de la condición, es decir entre ellos debes escribir todo lo que sucederá si la condición resulta ser verdadera. Observa ahora lo que sucede si existen sentencias de código que se encuentran fuera del inicio y cierre de bloque: if(plata >= 10000) { diversion++; } tiempo++; en este caso tenemos dos incrementos, el de la variable diversion y el de la variable tiempo, tiempo, sin embargo sólo una de ellas está condicionada a la cantidad de dinero que tengamos, dado que está encerrada entre los bloques. Este extracto de código tiene entonces dos posibles ejecuciones, el primero corresponde a cuando la condición es verdadera, sólo si esto ocurre la variable diversión hará su incremento, sin embargo la variable tiempo no se encuentra dentro del alcance de la condición y por ello hará su incremento ya que no depende de nada, el flujo contrario entonces hará que diversión no incremente su valor pero si lo hará la variable tiempo. Hasta ahora hemos visto como debiese comportarse el código cuando la condición es verdadera, pero muchas veces también nos gustaría definir un comportamiento para cuando esta es falsa, o dicho de otra forma definiremos el comportamiento de la condición para el UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
71
caso “sino “sino es verdadera”. Para ello utilizaremos la palabra reservada else (sino en inglés) la cual nos permitirá delimitar todas aquellas acciones que deben llevarse a cabo cuando la condición no se cumple, veámoslo con un ejemplo, en el caso anterior cuando disponíamos del dinero para salir entonces la diversión tenia un incremento, pues ahora supongamos que sino logramos salir entonces la diversión disminuye en uno, para ello escribiremos lo siguiente:
if(plata >= 10000) { diversion++; } else { diversion--; } Como puedes ver en el caso anterior si la condición no se cumple todo el código que se encuentre entre los primeros bloques no se ejecutará, dando paso a ejecutar todo lo que se encuentre dentro del else, realizando entonces el decremento de la variable. Volvamos ahora a agregar la variable tiempo, para que veas donde debe ir ubicada:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
72
if(plata >= 10000) { diversion++; } else { diversion--; } tiempo++; Al igual que el caso anterior la variable tiempo esta luego del if, por lo que su ejecución no esta condicionada ni al caso verdadero ni al falso, por ello al igual que en el caso anterior esta variable hará su incremento sin excepción, sin embargo la variable diversión en cambio tendrá un incremento o decremento en su valor sin escapatoria pero nunca ambas. La mayoría de las veces, el cumplimiento o no de una condición requiere ejecutar más de una sentencia de código, en ese caso bastará con agregar dentro de los bloques tanto del if como todo
else todas las que
desees, por ejemplo supongamos que si el dinero alcanza no sólo incrementa la diversión, si no que también descansas y que por otro lado si no alcanza el dinero para el paseo no solo te aburres, si no que además incrementa tu estrés.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
73
if(plata >= 10000) { diversion++; descanso++; } else { diversion--; estres++; } tiempo++; Así como muestra el ejemplo puedes agregar todas las instrucciones que desees en cualquiera de los bloques, por supuesto la cantidad de cada uno no debe ser igual, lo importante es que por claridad siempre escribas alguno, por ejemplo: if(plata >= 10000) { } else { diversion--; }
Aquí lo que tratamos de hacer es establecer sólo el caso del else diciendo que si el valor de la variable plata no es mayor o igual a $10.000 se decrementa el dinero, pero si es mayor o igual no pasa nada. Este caso puede ser UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
74
escrito de forma mucho más clara cambiando la condición de la siguiente forma: if(plata < 10000) { diversión--; } Dado que sólo else nos interesaba entonces ahora cambiamos la condición y en vez de preguntar si el valor de la variable plata es mayor o igual a $10.000 preguntamos lo contrario, es decir si el valor es menor, menor, de esta forma decimos que si esto se cumple entonces se decrementa la diversión quedando mucho más fácil de leer. Veamos ahora un caso un poco más complejo, no siempre tenemos la suerte de que una acción que deseamos ejecutar dependa de una sola condición por ejemplo, para salir de paseo tal vez necesites que el dinero alcance, pero adicionalmente que la temperatura se encuentre sobre los 17 grados, en este caso ambas condiciones
deben
cumplirse
y
por
ende
deben
compararse con el operador lógico Y, el cual debe simbolizarse con &&. if(plata >= 10000 && temperatura >17) { diversion++; descanso++; }
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
75
En este caso para que se incremente diversión y descanso ambas condiciones deben ser verdaderas. Veamos otro ejemplo, supongamos ahora que no deseas pasear sólo y para ir basta con que a cualquiera de tus mejores amigos les alcance el dinero para ir. En este caso la condición utilizada es O, dado que si el dinero requerido lo posee cualquiera de ellos nosotros también asistiremos al paseo (la condición es verdadera). if(plataAmigo1 >= 10000 || plataAmigo2>= 10000) { diversion++; descanso++; }
Utilizamos entonces || para representar la condición O, en este caso bastará que el valor en dinero de cualquiera de ellos (o ambas) supere el valor de $10.000.
Anidada. Las condiciones anidadas son condiciones que encuentras de forma muy habitual en la vida diaria, en muchas ocasiones una condición depende de otra, continuemos pensando que saldremos de paseo y aún nuestra limitante es el valor de la cuota y la temperatura, pero si vamos de paseo aún nos queda dilucidar si iremos en clase Premium o normal y ello dependerá del dinero que tengamos, ya sabemos que es igual o mayor a $10.000 y UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
76
asumamos que si llevamos sobre los $15.000 podemos darnos el gusto de viajar en Premium y gastar los $7.000 que vale el pasaje, de lo contrario pagaremos los $2.000 que cuesta el pasaje normal. Esta condición tiene sentido sólo si se ha cumplido la primera, es decir sólo si la temperatura es mayor a 17 y el dinero es igual o mayor a los $10.000, de ninguna forma tiene validez pensarlo al revés. if(plata >= 10000 && temperatura >17) { diversion++; descanso++;
if(plata >= 15000) { descanso++; plata = plata – 7000; } else { plata = plata-2000; }
} else { diversion--;}
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
77
En el código anterior si la condición que nos va a permitir salir de paseo se cumple, nuevamente incrementará la diversión y el descanso, pero adicionalmente nos lleva a otra condición, la cual nos permite saber, basándose en el dinero obtenido, cuanto pagaremos por el pasaje. Si el valor es superior o igual a $15.000 se restará de la variable plata $7.000 pesos e incrementará el descanso dada la comodidad que esto otorga, de lo contrario descontará $2.000. Este tipo de if anidados (uno dentro de otro) no tienen limitantes, vale decir puedes agregar una dentro de otra tantas estructuras de condición sea necesario, ya sea para el caso verdadero a para el falso. Este tipo de if son utilizados cuando necesites evaluar una condición que depende de una o más condiciones previas.
Múltiple En otras ocasiones no todo depende de una condición con un resultado verdadero o falso. Un buen ejemplo es simular el comportamiento felicidad que un alumno tiene según la nota que ha obtenido, convengamos que la felicidad es mayor mientras más alta la nota que obtenga, supondremos que las notas que un alumno puede obtener son C, B, A siendo C la nota más baja y A la más alta. Para calcular la felicidad diremos que si ha sacado una C el valor de la felicidad se multiplicará por 1, si es B por 3 y si es A por 5. Para lograr esto necesitamos conocer la nota preguntando si es A, si no lo es habría
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
78
que evaluar si es B o C, la forma de realizar esto es utilizando varios if, lo que podría volverse muy tedioso si las notas fuesen desde la A hasta la F, sin embargo (y para suerte nuestra) existe una estructura condicional llamada switch que nos permitirá definir varios flujos según
el
valor
programaremos
de todas
una las
variable, acciones
de que
esta
forma
deseemos
ejecutar para cualquiera de sus valores. switch (nota) { case ’a’ : felicidad*5; break; case ’b’: felicidad*3; break; case ’c’: f elicidad*1; elicidad*1; break; }
en el ejemplo anterior le pedimos a switch que evalué el valor de nota y definimos varios casos. Fíjate que cada caso esta compuesto por la palabra case y a su derecha el valor que esperamos tenga la variable evaluada, si es ‘a’ ejecutará todo lo que venga luego del signo : (dos puntos). En este caso multiplicará la felicidad*5 y hará un break, el break es importante y significa sign ifica corte o quiebre, la utilidad que presta es de cortar la ejecución del switch, dado que si el valor es “a”, no tiene mucho sentido verificar si es “b” o “c”. Al igual que en if si if si la condición se cumple puedes agregar cuantas sentencias desees UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
79
ejecutar, supongamos que si sacas una C tu animo decae temporalmente en 1. switch (nota) { case ’a’: felicidad*5; break; case ’b’: felicidad*3; break; case ’c’: { felicidad*1; animo--; } break; }
Sentencias de ciclo iterativo Los ciclos permiten que una o más sentencias de código se repitan hasta que una condición deje de cumplirse, es muy similar a lo que sucede con un conductor de la formula uno, el cual estará dando vueltas hasta que la cantidad de vueltas que ha dado deje de ser insuficientes para ganar la carrera, dicho en un lenguaje más informático si la cantidad de vueltas que debe dar el vehículo son diez, podremos expresarlo como mientras la cantidad de vueltas sea menor a 10, entonces debe seguir corriendo, pues en informática eso se expresa tal UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
80
cual como lo hemos mencionado. Veamos un ejemplo de uno de los ciclos más utilizados, el cual recibe como nombre el ciclo “mientras” al que de ahora en adelante lo conoceremos por su traducción al inglés while.
While while(vuelta<10) { vuelta++; } tiempo++; Aquí la ejecución ocurrirá de la siguiente forma, lo primero que hará while será evaluar si el valor de la variable vuelta es o no menor a 10, si el valor fuese por ejemplo 11, la condición no se cumplirá y para este caso se comportará muy similar al if dejando if dejando de ejecutar todo lo que se encuentre entre el inicio y cierre de bloques de manera que la variable vuelta no se incremente, sin embargo si el valor es 8, la condición será verdadera lo que provocará que si se ejecute todo lo que esta dentro de los bloques haciendo entonces el incremento de la variable. Cuando haya finalizado el incremento el while a diferencia del if no pasará directo a incrementar el tiempo, dado que cuando alcance el cierre de bloque volverá a preguntar por el valor de vuelta, el cual será 9 y dado que 9 aún es menor que 10 entonces while volverá a ejecutarse, incrementando el valor de vuelta en uno, al llegar al final de bloque nuevamente se va a UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
81
evaluar si vuelta es menor a 10, esta vez la condición no se cumple y es entonces cuando el ciclo termina para dar paso al incremento del tiempo.
For Existen varias estructuras que permiten iterar una o más líneas de código, el ciclo for es uno de ellos, pero antes de continuar, es importante aclarar que si bien entre ellos existen diferencias todos tienen el mismo objetivo, por ende no existirá nunca una limitante para uno u otro, pudiendo utilizar cualquiera de ellos cuando necesites iterar, sin embargo cada uno tiene una estructura y sintaxis diferente, el criterio de selección estará dado principalmente por el que te acomode más y de las necesidades que tengas. Volvamos al ejemplo de las vueltas en una pista de carreras presentada anteriormente. En aquel ejemplo el while tiene por misión cerciorarse de que la variable vuelta llegue a 10, pero no se preocupa del valor inicial de la variable, supongamos que las condiciones cambian y debes realizar el mismo algoritmo pero la variable vuelta debe comenzar siempre en cero. int vuelta=0; while(vuelta<10) { vuelta++; } tiempo++;
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
82
El ciclo while cumple a la perfección con nuestro propósito, sin embargo en el algoritmo hay 3 elementos a considerar: primero hay una inicialización se variable, la cual hemos agregado recientemente al solicitar que vuelta siempre comience en cero, luego tenemos una condición y un incremento, para este tipo de casos el for es principalmente provechoso dado que permite escribir de forma muy cómoda estos tres elementos. Veamos como luce este while convertido en un cliclo for. for(int vuelta=0; vuelta<10;vuelta++) { } tiempo++; Como puedes ver este ciclo contiene los tres elementos como parte de la declaración del ciclo, por ende el cuerpo de este ha quedado vacío, ya que hemos cambiado la lógica de incremento de la variable a otro lugar. La forma de ejecutarse no es igual que en while, while, para que lo entendamos mejor vamos a decir que el for está dividido en partes, la primera es una declaración, en la cual declaramos e inicializamos el valor de la variable vuelta, la segunda es la condición en la que decimos que vuelta no debe ser mayor a 10 y finalmente una sección donde incrementamos el valor de la variable vuelta en uno, entonces podemos decir que las partes son, declaración e inicialización, inicialización, condición e incremento, incremento, entonces la forma en la que el ciclo for funciona es la siguiente: lo primero que ocurre es la declaración e inicialización, con esto se asegura de que la variable exista y tenga un valor UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
83
inicial. Esta sección sólo se ejecuta una vez, vez, el siguiente paso es verificar si luego de la inicialización de la variable la condición se cumple, de de cumplirse ejecutará todo lo que este entre los inicios y cierre de bloques, el cual tenemos vacío por ahora. Al igual que el while el for intentará hacer una iteración, pero sólo a partir de la segunda vuelta y hasta que termine lo que hará es primero ejecutar la sección de incremento, haciendo que vuelta pase de cero a uno para luego verificar si la condición aún se cumple. De cumplirse volverá a ejecutar todo lo que se encuentre entre el inicio y cierre de bloques, al finalizar nuevamente hará el incremento y luego evaluará la condición. condición. Este proceso se repetirá hasta que la condición ya no se cumpla, como puedes ver la responsabilidad de inicializar, evaluar e incrementar esta toda definida dentro del for quedando entonces tiempo para preocuparse de otros elementos dentro del ciclo en sí, por ejemplo, contemos la cantidad de bencina que gasta por cada vuelta almacenándola en una variable llamada consumo. int consumoPorVuelta = 0; for(int vuelta=0; vuelta<10;vuelta++) { consumo += consumoPorVuelta; } tiempo++; el ciclo for se puede adaptar a varias situaciones gracias a que cualquiera de sus partes puede ser omitida, en el
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
84
siguiente ejemplo la declaración e inicialización de la variable es quitada del for y declarada antes. int vuelta=0; for(; vuelta<10;vuelta++) { }
Así
podemos
entonces
obtener
un
cuyo
for
comportamiento es idéntico al de un while. int vuelta=0; for(; vuelta<10;) { vuelta++; }
En este caso este for ha quedado exactamente como el ciclo while que vimos en un comienzo. Podrá parecer extraño pero incluso la condición puede ser omitida, sin embargo eso nos obliga a tener que agregar a nosotros una forma de quebrar el ciclo para que no este iterando de
forma
indefinida.
Sobre
los
quiebres
de
ciclos
hablaremos más adelante en la sección de break y continues, continues, pero por ahora como demostración de que todas las partes son opcionales lo haremos analizando el siguiente ejemplo:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
85
for(; ; ;) { } En este extraño caso no hay ninguna de las partes, sin embargo la forma en la que se ejecutará no es ningún misterio, ya que la ausencia de una condición da por defecto falso, así que luego de comprobar que no hay nada que inicializar, evaluará falso y omitirá la ejecución del ciclo for.
Do … While. Si del ciclo do while traducimos la palabra do veremos que significa “hacer”, pues esta es la principal diferencia con el ciclo while que vimos en una primera oportunidad, la condición es evaluada al final, es decir que toda la lógica agregada entre los inicios y cierres de bloque se ejecutará siempre al menos una vez. Supongamos ahora que el vehículo de carreras debe dar 10 vueltas seguidas para
hacer
obligatoria,
reconocimiento
de
la
pista
de
forma
pero si ya ha dado 10 entonces sólo se le
permitirá dar una. do { vuelta++; } while(vuelta<10); Como puedes ver la condición se encuentra al final, por lo tanto lo primero que sucederá es incrementar el número
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
86
de vueltas en uno, sin ninguna condición que pueda evitarlo. Supongamos que el valor de la variable acaba de incrementarse a 8, por lo tanto el corredor debe de forma obligatoria completar sus 10 vueltas, dado que 8 es menor a 10 la condición se hace verdadera dando paso a una nueva ejecución del bloque incrementando el valor de la variable a 9, con este valor la condición vuelve a evaluarse siendo verdadera dado que aún es menor a 10, en su última iteración la variable se incrementa a 10 y la condición se vuelve falsa, saliendo así del ciclo, sin embargo la diferencia está dada en que si vuelves a ejecutar este ciclo con un valor de 10 o superior, con un while el vehículo no hubiese sido aceptado, sin embargo con este ciclo no se evalúa la cantidad de vueltas al comienzo, por lo que las sentencias de código se ejecutarán haciendo que vuelta sea 11, luego de la primera ejecución el ciclo evaluará si debe proseguir, como la condición es falsa, el vehículo no dará una segunda vuelta.
Concepto de función Una función representa una porción de código (un conjunto de sentencias) que tienen por objetivo resolver un problema especifico. La mayoría de las veces este conjunto de instrucciones
es parte parte de de un algoritmo de
mayor tamaño, donde las funciones tienen como objetivo la división de un problema en problemas más pequeños y UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
87
sencillos, los que en su conjunto resuelven el problema mayor. Supongamos que deseas conocer el vuelto de la compra de varios productos del mismo precio, el precio de ellos no incluye el IVA por lo que hay que sumarlo, una vez se obtiene el total a pagar hay que determinar cuanto es el vuelto según el monto cancelado. Los datos de entrada para este problema son:
Cantidad de productos.
Precio.
Monto cancelado.
El valor del IVA
La salida:
Vuelto.
El proceso: Multiplicar el precio por la cantidad de productos, sumar el 19% para obtener obtener el valor a pagar y luego al monto cancelado restar el valor a pagar. Este proceso puede ser dividido en partes más pequeñas y
mucho
más
fáciles,
identifiquemos
algunos
sub
procesos. 1) Determinar el valor de los productos, este proceso es sencillísimo, los datos de entrada son sólo el precio y la cantidad, el proceso es una multiplicación y la salida el producto de ambos (sub total).
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
88
2) Calcular el IVA, la entradas es el sub total el cual calculamos en el paso anterior, el proceso agregar el 19% y la salida será el total. 3) Calcular el vuelto, los datos de entrada son el total y el monto cancelado, el proceso es restar al monto el total, la salida es el vuelto o el monto adeudado. Estos tres procesos son pequeños programas con una dificultad mucho menor que el total, por ende también son más sencillos de programar, lo importante es reconocer las entradas y las salidas de cada uno de ellos, así como también tener en consideración que alguna combinación de ellos dará el resultado final. Además de todo lo anterior el control y la corrección se hace más fácil, por ejemplo, supongamos que has entregado un software
encargado
de
realizar
distintos
cálculos
algebraicos y el resultado de ello son alrededor de 200 líneas de código, llena de bifurcaciones, sentencias switch y varios bucles, es probable que luego de un corto tiempo no recuerdes qué lógica usaste o para qué sirve cada una de las variables que utilizaste. Ahora tratemos de corregir el cálculo de la tangente de un circulo, lo que sin duda alguna podrá generar más de algún dolor de cabeza debido a que el código está en algún lugar dentro de las 200 líneas y lo que es peor no sabemos si el cambio del valor de alguna variable pueda afectar otros cálculos que la utilizan dentro del mismo ámbito, sin embargo si nuestro código esta dividido en pequeños sub programas, donde
cada
una
de
las
partes
reciben
nombres
apropiados y descriptivos de lo que hacen como por UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
89
ejemplo “AreaCirculo” “perimetroCuadrado” donde cada uno de estos programas pequeños tienen sus propias variables y un proceso que no depende del resto, por ende sólo tendrás que hacer la mantención de ese pequeño sub programa, donde el código es más limpio y fácil de entender, adicionalmente el cambio sólo afecta a las partes que lo utilicen y no a todo el programa.
Estructura de una función Existen dos tipos de subprogramas, las funciones y los procedimientos, los cuales pasaron a llamarse métodos con la programación orientada a objetos, la cual veremos más adelante, mientras tanto procederemos a estudiar en qué consiste cada una de ellas.
Procedimientos Representa una porción de código agrupada con un nombre que describa lo que hace. Las sentencias contenidas en dicho procedimiento pueden ser ejecutadas cuantas
veces
procedimiento
se puede
quiera, de
adicionalmente
forma
opcional
un
recibir
parámetros de entrada, con el fin de que en base a los valores de dichos parámetros el procedimiento ejecute alguna acción. Una característica importante del procedimiento es que el proceso que se ejecuta dentro resultado,
por
ejemplo,
si
nunca retorna un
necesitas
hacer
un
comportamiento al que le entregas dos valores para que UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
90
los sume, entonces el procedimiento deberá hacer el proceso de sumar ambos, pero no tendrá la facultad para devolverte el resultado, a cambio le puedes pedir que lo muestre por pantalla, que lo imprima u algún otro tipo de salida, pero nunca esperes respuesta. Otro buen ejemplo será un procedimiento que se llame correr, el que supongamos incrementa la variable cansancio en 1 y estado físico en 2, como puedes ver el procedimiento descrito se ha ocupado de cambiar valores a variables, pero no ha retornado un resultado. Los procedimientos pueden recibir de forma opcional parámetros, los parámetros como lo mencionamos antes tienen la función de determinar como se ejecutará dicho procedimiento.
Aclaremos
esto
un
poco
más,
supongamos que un procedimiento llamado saludar al ejecutarlo imprime por pantalla la cadena “hola amigo”, este
procedimiento
será
utilizado
por
el
programa
principal cada vez que necesite imprimir dicho mensaje, evitando así codificarlo varias veces, sin embargo el mensaje jamás variará por lo que aseguramos que el procedimiento
saludar
siempre
imprimirá
el
mismo
mensaje sin excepción. Si deseamos que éste tenga un comportamiento variable y que imprima “hola Anakin”, “hola Obi Wan” o algún otro nombre, entonces debemos determinar qué es lo que variará y qué no, de esta forma podemos determinar de forma muy fácil que el parámetro de entrada corresponde a un nombre (la parte variable) y que “hola” es parte del procedimiento. El proceso que se llevará a cabo es la unión (concatenación) de “hola” con UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
91
el valor de la variable que represente el nombre, de esta forma si deseas mostrar “hola Sebastián, tienes 29 años”, bastará con agregar un segundo parámetro de entrada que contenga la edad. De esta forma un procedimiento tendrá
todos
los
parámetros
que
desees,
debes
considerar que si decides entregar nombre y edad, entonces ya nunca más podrás entregar al procedimiento sólo la edad ya que los parámetros de entrada que definas en un procedimiento se convierten en una obligación para su ejecución, sin embargo puedes según los valores tomar acciones, por ejemplo si la edad es cero omitir la parte que dice “tengo xx años”. (Más ( Más adelante en el capitulo de POO veremos como una técnica llamada sobrecarga nos facilita esto aún más). Dado entonces que los procedimientos no retornan un valor, todos ellos utilizan la palabra reservada void para indicarlo, donde void significa la no existencia de un tipo de datos. A la derecha de la palabra reservada void indicaremos el nombre del procedimiento, el cual debe ser un nombre que describa lo que hace y cuyo proceso intelectual para inventarlo es nuestro, nuestro, por ejemplo “saludar” La tercera parte corresponde a los parámetros de entrada de nuestro programa, partiremos analizando un ejemplo que no recibe parámetros y que imprime el mensaje de “hola” como lo vimos antes.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
92
void saludar() { //tu código aquí } Como muestra el código anterior el procedimiento saludar se acompaña de paréntesis vacíos, lo que significa que no recibe parámetro alguno.
Las llaves representan el
inicio y término del cuerpo de nuestro procedimiento, en él debemos agregar toda la lógica referente a nuestro proceso saludar, el cual lucirá así: void saludar() { System.out.println(“Hola” ); ); } Para recibir parámetros debemos especificar para cada uno de ellos su tipo y nombre de la variable que contiene el valor de entrada. Agreguemos al código realizado la posibilidad de mostrar un nombre distinto cada vez. void saludar(String nombre) { System.out.println(“Hola Sy stem.out.println(“Hola ” + nombre); } Como puedes ver este método imprimirá el mensaje de “hola “ y lo concatenará con el valor de la variable nombre. La obtención del valor de dicha variable no es una responsabilidad del procedimiento saludar, recuerda que este es un sub programita cuya responsabilidad es UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
93
sólo generar el mensaje, por ende este comportamiento deberá ser utilizado por el programa principal, quien recurrirá a el cada vez que necesite generar un saludo, sin embargo el procedimiento como requisito para generar su objetivo requerirá que se le entregue algún nombre. Supongamos ahora que queremos mostrar también la edad, en ese caso debemos agregar un nuevo parámetro con su respectivo tipo, veamos como utilizar un
segundo
parámetro
de
entrada
para
nuestro
procedimiento. void saludar(String nombre, int edad) { System.out.println(“Hola ” + nombre + “, tengo “ + edad + “ años”); } A partir del segundo parámetro en adelante debemos utilizar una coma para separarlos, de esta forma podrás agregar cuantos parámetros consideres necesario como requisito para ejecutar tu procedimiento. Por otra parte el cuerpo de nuestro procedimiento llevará todas las líneas de código que desees, sin embargo debes tener muy presente de que los inicios y cierres de bloque definen el ámbito (la frontera) de nuestra función, esto significa que todas las variables que allí se declaren estarán disponibles sólo dentro de la función esta regla también es valida para los parámetros que recibe. veamos un ejemplo:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
94
void saludar(String nombre, int edad) { int codigo = 66; System.out.println(“Hola ” + nombre + “, tengo “ + edad + “ años y mi código de trabajador es:” es:” + codigo); } void despedir() { System.out.println(“chao, recuerden que que mi nombre es ” + nombre + “ y tengo “ + edad + “ años y mi código de trabajador es:”
+ codigo);
} El procedimiento saludar tiene 3 variables declaradas en su ámbito, dos de ellas son nombre y edad, cuyas valores vienen asignados desde otro lugar del código y son recibidos como una entrada. La variable código en cambio es declarada como una nueva variable e inicializada dentro del método, pero las tres tienen el mismo ámbito pudiendo usarse cualquiera de ellas dentro de los límites del procedimiento. Si miramos el procedimiento despedir en cambio aseguraremos que existen 3 errores, los cuales corresponden a la utilización de las variables nombres, edad y código, ya que ninguna de las tres existe en este ámbito. Si desean usarse hay que recibirlas como parámetro o declararlas dentro del método, ambas alternativas son correctas, pero la diferencia la determinará si deseas que los valores sean asignados dentro del método (el caso de código en el UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
95
método saludar) o como parámetros cuyo uso representa un valor que viene desde fuera del procedimiento. Dado que como lo mencionamos antes una variable declarada dentro de un procedimiento define el ámbito en el que la variable vive, veamos el siguiente código:
void saludar() { int var1 = 66; } void despedir() { int var1 = 66; } En el código anterior la variable var1 ha sido declarada en ambos procedimientos, esto no provocará un error ya que ambas variables viven en un ámbito diferente y el cambio en el valor de alguna de ellas no afectará el valor de la otra, ya que si bien comparten un mismo identificador son variables totalmente distintas.
Función Una función es muy similar a un procedimiento, con la salvedad de que la función debe retornar algún valor, o dicho de otra forma el proceso dentro de la función debe generar algún resultado en algún tipo de datos conocido UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
96
para retornarlo a quien llame al procedimiento. Un ejemplo será el comportamiento sumar, el cual recibirá dos parámetros y cuyo resultado de la suma no será una impresión por pantalla, el resultado generado será devuelto a quien llame a la función como un valor representado por alguno de los tipos de datos que tenga el lenguaje, la función utiliza la palabra reservada return para realizar el retorno del resultado del proceso, por ello return siempre debe estar presente y su ejecución significa también el final de la función, ya que una vez se retorna el resultado significa que la función ha finalizado. int suma(int a, int b) { int c = a + b; return c; } El código anterior es un ejemplo de la función suma, en este caso y al igual que en el procedimiento, la función recibe dos parámetros de tipo entero, la diferencia está dada en que void ha sido remplazada por int, int, el cual define el tipo de dato que la función va a retornar, en este caso se ha utilizado int dado que la suma de a y b representarán un entero. Así una función podrá retornar cualquier tipo de datos conocido por el lenguaje. Luego de la operatoria encontraras la sentencia return c, la cual contiene el resultado de la operatoria a+b y cuyo resultado concuerda con el tipo que explicitamos que la función retornaría.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
97
Llamada a una función En
la
programación
estructurada
las
funciones
y
procedimientos acompañan el método principal, llevando parte de la lógica a ellas, las cuales tienen como propósito resolver problemas más pequeños, hacer más fácil la programación y reutilizar el trabajo ya hecho. Una función que nos indique si un archivo existe en nuestro disco duro es un buen ejemplo, la próxima vez que se necesite verificar la existencia de un archivo bastará con llamar a dicha función entregando la ruta del archivo a buscar, estas tareas específicas no tienen sentido por sí solas, casi siempre son parte de un programa que tiene algún propósito mayor y este programa es el encargado de llamar a una o mas funciones para lograr el objetivo. Durante este capitulo veremos cómo utilizar las funciones desde el punto de vista estructurado y más adelante veremos
como
las
funciones
son
utilizadas
en
la
programación orientada a objetos. La forma en la que las utilizaremos dependerá de dos factores, lo primero a considerar es si lo que estamos llamando es un procedimiento o función, ya que la primera diferencia entre ellos es su retorno. Recuerda que un procedimiento no retornará nada, sin embargo si llamamos una función debemos esperar algún resultado, el otro factor corresponde a los parámetros que reciben, para ambos casos hay que considerar cuantas variables hay que enviarle al procedimiento o función y de qué tipos son. UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
98
Comenzaremos con el caso más sencillo e iremos transformando un programa simple en un programa dividido en funciones, supongamos que tenemos el siguiente código: public class JavaApplication2 { public void miEjemplo() { int fechaNacimiento=1982; String nombre = “sebastian” = “sebastian” ; int fechaActual = 2012; int edad = 0; edad = fechaActual - fechaNacimiento; String correo = nombre + edad +
“@”
+
“empresa.cl” System.out.println("Hola mi nombre es " + nombre + ", tengo " + edad + "años y mi correo es " + correo); } } Este pequeño programa presenta el nombre y la edad de una persona, la cual se ha calculado sólo considerando el año de nacimiento, por lo que en este simplificado ejemplo es posible que la falta de la inclusión de los meses produzca alguna diferencia, el cálculo que se almacena
en
una
variable
edad
que
es
después
desplegada como parte del mensaje, además el correo de UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
99
la persona también se muestra, pero previo a ello se genera basándose en el nombre y la edad de la persona y se le agrega @empresa.cl. Si hacemos un pequeño análisis aquí hay 3 pequeñas funcionalidades que pueden ser fácilmente llevadas funciones y procedimientos. 1)Calculo 1) Calculo de la edad 2)Generación 2) Generación del correo. 3)Presentación 3) Presentación de la persona mediante una impresión. El
paso
siguiente
será
determinar
cómo
debemos
modularizar estas funcionalidades, especificando cuales serán procedimientos, cuales deben ser funciones y que valores deben recibir. Si hacemos un pequeño análisis nos daremos cuenta que algunas variables como por ejemplo el nombre, deben ser conocidos por dos de los tres procesos. Primero la debemos utilizar para la generación del correo y luego en el paso número tres para la impresión, esto nos indica rápidamente que el nombre no es una variable exclusiva de ninguno de los dos, ya que si se declara dentro de alguno de los dos métodos la variable y su valor estaría sólo disponible dentro de él, por lo tanto la variable nombre debe declararse en el método miEjemplo ya que este será el encargado de llamar a las demás funciones pudiendo así pasarlas de una a otra sin perder la variable. Esto se deberá a que las funciones que vaya llamando miejemplo crearán sus variables que tengan declaradas, pero al finalizar su ejecución todas ellas serán destruidas, sin embargo, miEjemplo
estará activo durante todo el
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
100
proceso, llamando y ejecutando las funciones que en el programamos. Comencemos entonces a desmenuzar este problema en pequeños
“problemitas”,
analicemos
el
proceso
del
cálculo de la edad. Para realizarlo lo que necesitamos es la fecha de nacimiento y la fecha actual, el proceso es la resta de ambas y el resultado la edad, por lo tanto cuando miejemplo llame la función que se encarga de calcular la edad debe especificar ambos parámetros y luego esperar la respuesta de la función, la cual corresponde a la edad calculada. Este valor de retorno nos indica que la función no puede ser un procedimiento, dado que debe retornar el valor para que luego dicho valor sea mostrado en el mensaje, entonces nuestro pequeño programa queda así: int calcularEdad(int fechaNacimiento, int FechaActual) { int edad = fechaActual- fechaNacimiento; return edad; } La función recibe ambos parámetros como un entero y retorna la resta de ellos, valor que también es de tipo int. La variable edad que está declarada al interior sólo vive dentro de calcularEdad y no es compartida con nadie, sin embargo la última línea de código se encarga de retornar
el
valor
de
tipo
entero
que
aseguramos
retornaríamos. Debes tener tener cuidado con no confundirte, la función no retorna una variable, lo que hace es UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
101
devolver el valor de ella, ella, según sea el resultado debes imaginar que lo que allí dice es algo así como: return 10 o return 39 según el resultado del cálculo. Veamos ahora la generación del correo, para ello las entradas son, la edad y el nombre de la persona, el proceso es una concatenación de ellos y el resultado (el valor a devolver) el correo, este proceso entonces lucirá así: String generarCorreo(String nombre, int edad) { String email = nombre + edad + “@”
+ “empresa.cl”;
return email; } En este caso el tipo de retorno será un String y ello se notifica a la izquierda del nombre de la función, también recibe dos parámetros los cuales son el nombre y la edad. Fíjate que la edad se asume viene calculada, ya que no es responsabilidad del método generarCorreo realizar este calculo, para ello hemos escrito otra función. Luego de la concatenación el método retorna el valor de la variable email hacia miEjemplo. miEjemplo. Finalmente el módulo que realiza la impresión será un procedimiento, ya que no hay un valor que deseemos retornar hacia mi Ejemplo, Ejemplo, sin embargo para lograr la impresión necesitaremos el nombre, la edad y el correo. void imprimirDatos(String nombre, int edad, String correo) UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
102
{ System.out.println("Hola mi nombre es " + nombre + ", tengo " + edad + "años y mi correo es " + correo); } En este caso la impresión no es un valor que vayamos a devolver, por esto el procedimiento no lleva return y en su firma informa que el tipo de retorno es void, vale decir que no hay retorno. Para unir todo el método miejemplo será el encargado llamar a todas las funciones y dar el orden lógico de ejecución, luego de recodificar el código el miejemplo lucirá así: public class JavaApplication2 { public void miEjemplo() { int fechaNacimiento=1982; String nombre = “sebastian” = “sebastian” ; int fechaActual = 2012; int edad = calcularEdad(fechaNacimiento,fechaActual); String correo =generarCorreo(nombre,edad); imprimirDatos(nombre,edad,correo); } }
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
103
Como puedes ver leer el programa es mucho más sencillo ahora, ya que palabras como calcularEdad dejan de forma más explicita lo que hace esa línea, fíjate que para ejecutar ese método es necesario pasar dos parámetros, estos deben ir separados por coma y en el mismo orden en el que la función esta declarada, al igual que antes no es la variable la que se entrega sino el valor de ellas, también
es
valido
entonces
solicitar
a
la
función
calcularEdad que lo haga llamándola de la siguiente forma: public class JavaApplication2 { public void miEjemplo() { String nombre = “sebastian”; int edad = calcularEdad(1982 calcularEdad(1982,,2012); 2012); String correo =generarCorreo(nombre,edad); imprimirDatos(nombre,edad,correo); } } En este caso a la llamada a “calcularEdad “calcularEdad”” se le entregan los valores explícitamente, eso también esta correcto ya que ambos valores son recibidos en las variables declaradas dentro de la función, se resta y se retorna el resultado, el cual guardamos en una variable declarada dentro de miejemplo que se llama edad. edad.
Una nota importante, si bien la variable de la que se retorna el valor en calcularEdad se llama igual que la
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
104
variable en la que miEjemplo lo recibe no significa que esto deba ser así, recuerda que las variables están en ámbitos distintos y por ende son variables totalmente independientes, por esto los nombres que utilicen no generaran alguna diferencia, pudiendo ellas llamarse iguales o tener nombres diferente, recuerda que la variable edad de miejemplo lo que recibe es un número (el valor de la variable edad de calcularEdad calc ularEdad)) Al igual que en calcular edad en generarCorreo debemos recibir el valor de retorno, el cual en este caso es una concatenación que simula el correo del usuario y que almacenamos en una variable llamada correo. Finalmente para llamar a imprimirDatos no hay una asignación
(signo
igual)
dado
que
este
es
un
procedimiento que ejecuta una o más líneas de código pero no
retorna un valor, sin embargo si recibe tres
parámetros los cuales al igual que antes deben ser entregados en el mismo orden y con sus tipos de datos correspondientes. El código completo quedará de la siguiente forma, donde los procedimientos y funciones son agregados al código, no importa su orden, sólo importa el orden en el que miejemplo los utiliza, siendo entonces miejemplo el punto de inicio de nuestro algoritmo y de allí se ejecuta todo lo demás.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
105
public class JavaApplication2 { public void miEjemplo() { String nombre = “sebastian”; int String
edad correo
=
calcularEdad(1982,,2012); calcularEdad(1982 2012); =generarCorreo(nombre,edad);
imprimirDatos(nombre,edad,correo); } void imprimirDatos(String nombre, int edad, String correo) { System.out.println("Hola mi nombre es " + nombre + ", tengo " + edad + "años y mi correo es " + correo); } String generarCorreo(String nombre, int edad) { String email = nombre + edad + “@”
+ “empresa.cl”;
return email; } int calcularEdad(int fechaNacimiento, int FechaActual) { int edad = fechaActual- fechaNacimiento; return edad; } }
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
106
Con las llamadas a las funciones y/o procedimientos puedes utilizar todas las combinaciones que gustes, observa este ejemplo, el cual hace lo mismo pero de otra forma, he aquí el código y luego la explicación. public class JavaApplication2 { public void miEjemplo() { String nombre = “sebastian”; int edad = calcularEdad(1982,2012); imprimirDatos(nombre,edad, generarCorreo(nombre,edad)); } void imprimirDatos(String nombre, int edad, String correo) { System.out.println("Hola mi nombre es " + nombre + ", tengo " + edad + "años y mi correo es " + correo); } String generarCorreo(String nombre, int edad) { String email = nombre + edad + “@”
+ “empresa.cl”;
return email; } int calcularEdad(int fechaNacimiento, int FechaActual) { int edad = fechaActual- fechaNacimiento;
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
107
return edad; } } En este caso la línea que asignaba el correo ha sido eliminada, sin embargo para obtener el correo y luego poder imprimirlo remplazamos la variable correo que ya no está por la llamada al método generarCorreo, esto es posible ya que el método lo que solicita es un string con el correo y dado que el orden de ejecución es desde adentro hacia afuera, primero se ejecutará la función generarCorreo la cual retornará un String y cuyo valor es entregado a imprimir. De esta misma forma también podrás llamar a funciones desde otras funciones y/o procedimientos
como
muestra
el
siguiente
cambio
realizado a imprimir. void
imprimirDatos(String
nombre,
int
edad,
String
correo) { System.out.println("Hola mi nombre es " + nombre + ", tengo
"
+
edad
+
"años
y
mi
correo
es
"
+
generarCorreo(nombre,edad); generarCorreo(nombre,edad ); } En
este
caso
para
obtener
el
correo
le
pedimos
directamente desde dentro de imprimirDatos.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
108
Relación de la función con el método de una clase. Arreglos Un arreglo es un grupo de variables de un mismo tipo, las cuales son referenciadas con un mismo nombre. Los arreglos existen en más de una dimensión, siendo los arreglos de una dimensión (o sólo arreglos) los más comunes
y
los
de
dos
dimensiones
(matrices),
afortunadamente para los conocedores de lenguajes como C o C++ los arreglos y matrices serán algo familiar, sin embargo no son exactamente iguales, ya que existen algunas diferencias en su sintaxis.
Unidimensionales Los arreglos de una dimensión, permiten almacenar una cantidad N de variables de un tipo, la declaración general de un arreglo es la siguiente: Tipo identificador [ ];
Por ejemplo:
Para este caso la declaración ha creado una variable llamada mes que permitirá referenciar a nuestro arreglo, UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
109
sin embargo aún el arreglo no se ha creado y mucho menos definido su tamaño, esto significa que en mes aún no es posible almacenar valores. Para obtener un arreglo de tamaño n, se debe ejecutar la siguiente sintaxis.
• Declaración = new tipo[tamaño]
De esta forma se reservará el espacio de memoria que permitirá almacenar una n cantidad de elementos, la palabra clave new crea dicho arreglo con los valores por defecto del tipo especificado, por ejemplo, la siguiente declaración declara y construye un arreglo de tamaño 12, donde cada entero entero dentro dentro del arreglo es inicializado en 0:
mes es un arreglo capaz de almacenar 12 números de tipo entero, los elementos están almacenados de forma adyacente y se pueden referenciar utilizando un número entre 0 y 11 (12 en total). Por ejemplo, el siguiente código almacena el valor de 10 en la posición 1 del arreglo, de forma adicional, si cada posición tuviese directa equivalencia con el nombre de un mes, la posición 1 seria febrero, ya que, 0 es la primera posición y equivaldría a enero, luego 1 es igual a Febrero.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
110
A pesar de no ser muy común los arreglos también pueden ser inicializados, por ejemplo el siguiente código crea el arreglo mes con un valor para sus 12 enteros:
Note, que de esta forma el tamaño del largo está indicado por la cantidad de elementos con el que se inicializa.
El ciclo for estudiado en capítulos anteriores es el utilizado de forma más común en la operatoria con arreglos, el siguiente código muestra la forma de imprimir todos los valores del arreglo mes:
La salida del dicho código será:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
111
Arreglos de dos dimensiones . Los arreglos multidimensionales son en realidad arreglos que contienen otros arreglos. Es muy común asociar un arreglo multidimensional con una matriz, sin embargo las matrices son sólo una posibilidad dentro de la enorme cantidad de combinaciones que permite trabajar con arreglos de arreglos. El siguiente código permite declarar un arreglo en dos dimensiones.
Para este caso nuestro elemento es de tipo rectangular, dado por 4 filas y 5 columnas, como muestra la siguiente tabla. [0][0] [0][1] [0][2] [0][3] [0][4] UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
112
[1][0] [1][1] [1][2] [1][3] [1][4] [2][0] [2][1] [2][2] [2][3] [2][4] [3][0] [3][1] [3][2] [3][3] [3][4]
Por lo tanto, toda operatoria con arreglos de dos dimensiones, debe especificar las dos dimensiones para poder referenciar un elemento dentro de la estructura, por ejemplo, el siguiente código muestra cómo se asigna el valor de 10 al tercer elemento de la segunda fila.
La siguiente tabla muestra los valores que contiene la matriz. 0
0
0
0
0
0
0
10
0
0
0
0
0
0
0
0
0
0
0
0
Note que la tabla anterior muestra los valores por defecto que tiene nuestra matriz, sin embargo es importante comentar que la tabla muestra una vista conceptual de cómo se almacenan los datos en una matriz, dado que en la memoria física los datos no son almacenados con esta estructura. El siguiente algoritmo permite poblar una matriz de 4 x 5 con los números desde el 1 al 20:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
113
Arreglos de arreglos. Es muy usual que cuando se trabaja con arreglos de dos dimensiones,
muchos
asociamos
inmediatamente
la
estructura con una forma rectangular, si vamos más allá, descubriremos que en Java también pueden declararse arreglos multidimensionales de tres dimensiones de la siguiente forma:
sin embargo, es sólo el comienzo, ya que, en Java puedes agregar todas las dimensiones que desees ¿Cómo es eso posible? posible? la respuesta no es tan compleja como como se piensa, sucede que una matriz, en realidad no es un rectángulo, sino que, arreglos de arreglos, por ejemplo,
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
114
la matriz vista anteriormente de 4 filas y 5 columnas, en la memoria se encuentra almacenada de la siguiente forma:
Como se puede apreciar, existe en realidad un arreglo de 4 elementos, pero cada uno de ellos es además un arreglo de 5 posiciones, por ello la anotación de una matriz es [][] (arreglos de arreglos), por ende, cuando se escribe una referencia a algún elemento como:
Se está en realidad diciendo, que en el arreglo que ocupa la posición 1 (es decir el segundo elemento, dado que comienza de cero) almacenamos en su posición 2 (la tercera) el valor de 10. De esta forma el siguiente ejemplo
muestra
como
luce
un
arreglo
de
dimensiones:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
tres
115
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
116
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
117
Introducción a la Programación Orientada a Objeto. Características generales de la Características programación orientada a objetos. Muchas personas al escuchar por primera vez la frase “programación
orientada
a
objetos”
la
asocian
inmediatamente a un programa o una tecnología, sin embargo dicha asociación es incorrecta, por ello antes de adentrarnos en el mundo de la programación orientada a objetos (POO. desde ahora en adelante) y sus beneficios vamos a aclarar algunos puntos importantes.
Qué es la programación orientada a objetos La programación orientada a objetos es un conjunto de normas, que se basan en la idea de construir un software de forma mucho más cercana a la vida real, simplificando las tareas de desarrollo de software y entregando importantes beneficios a los programadores, los cuales se benefician principalmente de la reutilización de código, evitando así volver a realizar tareas comunes una y otra vez.
(Importante) La POO no es aplicable sólo a JAVA, la POO es
una
norma
(una
forma
de
hacer
las
cosas)
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
118
independiente del lenguaje, por ende, esta norma puede ser utilizada no sólo con JAVA, sino que con cualquier lenguaje orientado a objetos del mercado, como por ejemplo, C#, C++ o PHP desde su versión 5.0. Esto representa un importante beneficio para el programador, ya que la transición de aprender un lenguaje orientado a objetos distinto se hace más fácil cuando ya dominas alguno de ellos.
Antes de continuar, es imprescindible comprender a qué nos referimos con Objeto y para ello hagamos el siguiente ejercicio: miremos a nuestro alrededor y veamos los objetos que nos rodean, fíjate que cada elemento que miras es un objeto y que para cada uno de ellos existen propiedades, un comportamiento y un estado.
En informática nos referimos a un objeto como el bloque de construcción de un programa orientado a objetos. Un programa que utiliza la Orientación a Objetos (desde ahora
en
adelante
OO)
básicamente
contiene
una
colección de objetos.
(Definición) Un objeto es la instancia de una clase, la cual contiene propiedades, comportamientos, estados y una identidad que lo hace único.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
119
(Definición)Un objeto es un concepto, abstracción o cosa con un significado y límites claros en el problema en cuestión (Rumbaugh)
(Definición) Es aquel que posee propiedades, estado y comportamientos. (Booch)
Atributos Piensa en un televisor y trata de identificar qué atributos este contiene, algunos de los más visibles son:
Color
Marca
Modelo
Tamaño
Peso
(Definición)Podemos definir entonces un atributo como la característica de un objeto, la cual posee un valor.
Por ejemplo el atributo color puede tener los valores: verde, café, blanco, etc. Así como la propiedad peso puede ser: 3 kilos, 4 kilos, etc. No es válido entonces afirmar que 2 metros es un atributo, debido a que la expresión “2 metros” es en realidad el valor de un atributo. Ahora si bien un objeto puede tener muchas propiedades,
no
todas
son
útiles
al
momento
de
programar, pues sólo las que son útiles en el contexto del UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
120
problema deben ser consideradas. Por ejemplo, si estoy creando un objeto que me permita representar al cliente de un banco es muy probable que la estatura que tenga no sea un dato relevante para el proceso que realiza el banco.
Comportamientos (Definición)Estos se refieren a todas aquellas actividades que pueden llevarse a cabo con el objeto, los cuales se ejecutan como respuesta a un mensaje proveniente desde el usuario u otros objetos. Volvamos al ejemplo del televisor y pensemos en los distintos comportamientos que un televisor tiene, los cuales son por p or ejemplo:
Encender
Apagar
Cambiar canal
Cambiar el volumen.
Con estos comportamientos entramos a analizar una característica básica de los sistemas de información en general, y dice que cualquier proceso que estos realicen, afecta al valor de un atributo, ahora los valores de dichos atributos alguien los produce y el software los consume para realizar un proceso. En el caso de los objetos, los datos generalmente están asociados a un atributo y el comportamiento del objeto utiliza estos datos. Así se da una relación directa entre el dato y el comportamiento, el UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
121
comportamiento afecta al atributo y el valor del atributo afecta al comportamiento. Por ejemplo, si creamos una clase que represente un plumón, podemos identificar un comportamiento básico que es rayar (el plumón no escribe lo haces tú), ahora, un atributo del plumón es la cantidad de tinta que este posee, si te fijas si no tengo tinta no puedo rayar y cada vez que rayo, la cantidad de tinta disminuye. De esta forma la propiedad define al comportamiento y el comportamiento afecta a este atributo.
Estados (Definición)Es información que posee el objeto, la cual puede ser fija o variable. Por ejemplo, en el caso de nuestro televisor algunos estados son:
Encendido
Apagado
En silencio (mute).
El estado permite definir los comportamiento que el objeto puede o no realizar, por lo tanto no sólo se trata de los valores de las propiedades del objeto, sino de como este se comporta con los valores que está manejando.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
122
Clase A menudo en informática se utiliza la palabra clase y objeto como sinónimos, sin embargo dicha asociación es incorrecta.
(Definición)Una clase es la definición de un objeto, de sus atributos,comportamientos y estados, es muy similar a lo que para un arquitecto es el plano de una casa, en él se definen la posición de las puertas y las dimensiones que estas tendrán. En informática, por ejemplo, la clase que permite crear objetos de tipo persona definirá atributos como el Rut, nombre y edad y comportamientos como comer, jugar, cantar y estudiar.
Continuando con el ejemplo del televisor, pensemos en qué sucede si ahora ponemos frente a nuestra vista 3 televisores, ¿qué es lo que tienen en común? La respuesta
a
la
pregunta
sería,
atributos,
comportamientos y estados, debido a que los 3 son el mismo objeto. Nótese, Nótese, que la expresión “el mismo objeto” es es en realidad más compleja de lo que parece, debido a que ¿son en realidad el mismo objeto? Definitivamente no, es verdad que tienen los mismos atributos, por ejemplo, ambos tienen tamaño, marca y modelo, recuerde que los valores de las propiedades pueden variar, es decir uno puede ser de 22 pulgadas y los otros dos de 15 sin embargo los tres comparten un atributo llamado “cantidad de pulgadas”, donde lo que
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
123
cambia
es
su
valor,
así
mismo
comparten
los
comportamientos de encender, apagar y los estados de encendido y apagado. Dado lo anterior podemos decir entonces que los objetos siempre se pueden identificar como un objeto distinto a otro, a este concepto se llama identidad.
(Importante) La identidad es un concepto que no está asociado a los valores de los atributos o diferencias entre los comportamientos que estos puedan tener, es decir, si para el ejemplo anterior los tres televisores tuviesen la misma cantidad de pulgadas, la misma marca y modelo, aun así son 3 objetos que poseen su propia identidad. Recordemos que uno de los principales beneficios de la programación orientada a objetos dice que permite la reutilización de código, pues bien, ahora veremos como las clases aportan de manera significativa en este proceso. Para simplificar aún más la explicación, vamos a recurrir nuevamente a nuestro arquitecto, el cual tiene la difícil tarea de construir un gran condominio de 20 casas iguales, ¿es necesario que nuestro arquitecto idee, calcule, mida y dibuje 20 planos de casas? Pues no, el sólo ideará un plano ¿y por qué?, sencillo, porque no es necesario, debido a que todas las casas tienen mucho en común y a partir de un solo plano (clase) se puede construir una N cantidad de casas (objetos).
(Importante) de allí proviene la definición de objeto, la cual dice que un objeto es la instancia de una clase,
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
124
debido a que todos los objetos son construidos a partir de una misma clase.
Veamos como habría que construir una clase para satisfacer el requerimiento de registro del personal de una clínica, del cual sabemos que existen alrededor de 1000 trabajadores entre los que se incluyen doctores, enfermeras, dentistas, administrativos, personal de aseo, etc.
Solucionar este problema es mucho más sencillo de lo que parece. Primero tenemos que definir qué información se desea obtener de cada uno, como se puede notar, todos tienen algo en común y es que todos son personas, por ende comparten comportamientos y propiedades y de ellas registraremos: el Rut el cual representa un usuario como único (identidad), nombres, apellidos, edad y departamento en el que trabajan.
Por ende la clase que debemos crear debe tener las siguientes propiedades:
Rut (representado por una combinación de números y
caracteres).
Nombres y apellido (representado por una combinación
de caracteres).
Edad (representada por un número)
Departamento. (representada por una combinación de
caracteres)
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
125
Adicionalmente
podemos
agregar
algunos
comportamientos:
Verificar edad (el cual verifica que la edad sea mayor a
18 años)
Una vez nuestra clase (definición de cómo es un objeto) está resuelta, debemos utilizar un lenguaje como JAVA para crear la clase en nuestro computador y a partir de ella podemos crear todos los objetos que deseemos con distintos
valores
en
sus
propiedades
los
que
representarán a las personas que laboran en la clínica. Finalmente
utilizando
complementar
lo
la
anterior
tecnología creando
Java
debemos
aplicaciones
que
permitan a los usuarios interactuar a través de una aplicación Web o de escritorio que les permita ingresar y posteriormente ver la información referente al personal.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
126
En la programación Orientada a Objetos existen 4 pilares fundamentales que hay que conocer antes de arriesgarse a programar clases, el profundo conocimiento de ellos, te permitirá identificar cómo crear mejores clases y ahorrar una gran cantidad de trabajo, así como disminuir las posibilidades de cometer errores:
Abstracción.
Encapsulamiento.
Herencia.
Polimorfismo.
Abstracción (Definición)La abstracción corresponde a la ignorancia selectiva con la que enfrentamos un problema, el concepto
de
abstracción
nos
dice
que
debemos
preocuparnos sólo de lo importante e ignorar de manera selectiva lo que no lo es. Un ejemplo de abstracción es el siguiente,
sabes
que
algunas
propiedades
correspondientes a una persona serían: Edad, Nombre, Rut,
Peso,
Estatura,
género,
masa
muscular,
nacionalidad. ¿Pero qué sucede si las personas que deseamos gestionar mediante un software son jugadores de fútbol? En dicho caso algunas propiedades candidatas a tomar en cuenta son: número de camiseta, cam iseta, equipo en el que juega, edad, nacionalidad y cantidad de goles realizados. Observa que en esta ocasión de manera selectiva hemos obviado propiedades como alimento preferido, el color que más le gusta, color de ojos, etc.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
127
Que si bien son propiedades comunes para las personas, para un futbolista no son relevantes.
Encapsulación (Definición)Es la característica que tienen las clases de ocultar la complejidad de sus comportamientos, mediante la presentación al usuario de una interfaz, la cual responde a peticiones a través de métodos sin la necesidad de exponer los medios utilizados para brindar un resultado. El encapsulamiento es un concepto con el que lidiamos a menudo sin darnos cuenta, por ejemplo, si volvemos al caso
del
televisor
citado
antes
y
recordamos
los
comportamientos que este posee, nos daremos cuenta que encender y apagar el televisor son comportamientos que utilizamos a menudo, pero que afortunadamente la complejidad del proceso, es decir el “qué “qué sucede para que se encienda o apague” está está oculta para nosotros (el usuario), curiosamente, tampoco nos interesa saber como funciona. La razón de esto se debe a que el televisor expone al usuario una interfaz que presenta de forma comprensible las entradas (lo que necesita para encenderse) y las salidas (el resultado) , entonces, el usuario envía un mensaje al televisor el cual es enviado a través del control remoto. Por otra parte el televisor en su interfaz, a través del receptor o el botón de encendido, nos indica qué es lo que necesita para comenzar a ejecutar el comportamiento “encender”, entonces, sin UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
128
importar si el mensaje es enviado a través de la pulsación del botón o por medio del control remoto, el mensaje es entregado como dato de entrada necesario para la ejecución, así, el televisor de forma oculta (encapsulada) ejecuta
todos
los
mecanismos
para
encenderse.
Finalmente el usuario recibe como recompensa un televisor preparado para comenzar a disfrutar de su programa preferido.
Herencia La herencia es una de las más interesantes bondades que presenta
la
POO.
Gracias
a
ella
es
posible
una
jerarquización de las clases y una mayor reutilización de código, donde las clases en lo más alto de la jerarquía contendrán un conjunto de funcionalidad comunes que utilizarán las clases de niveles inferiores, las cuales agregan nuevas funciones que son cada vez más específicas,
(Definición)La herencia define una relación entre clases, en
la
cual
una
clase
comparte
su
estructura
y
comportamientos con otra. El ejemplo más claro de la herencia es la especie humana, donde la herencia se da en un conjunto de atributos físicos que se van pasando de generación en generación (nuestros atributos), incluso los humanos heredamos a nuestros hijos una serie de comportamientos que son propios de lo humanos y otros que vamos modificando (especializando) con el tiempo.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
129
Asociación.
Aplicaciones básicas Como habíamos conversado anteriormente, Java es un programa OO, lo que significa que sólo se compone de objetos y que ellos son instanciados (construidos) a partir de una clase, la cual es la que define los atributos y comportamientos que puede realizar. Afortunadamente para nosotros, no todos los objetos que se necesitan comúnmente en un software debemos construirlos a partir de una clase desarrollada con esfuerzo nuestro, esto debido a que Java ya ha identificado muchos objetos que los programadores necesitan y para cada uno de ellos
ya
existe
una
clase
que
contiene
toda
su
funcionalidad. Si bien, ya vimos que al igual que otros UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
130
lenguajes de programación el comienzo de ella es el método main, no debemos olvidar que en un programa desarrollado bajo la OO debe contener al menos una clase, es por ello que nuestro método main se encuentra dentro de una, tal y como muestra la imagen a continuación:
Para este caso nuestro programa comienza por la clase HolaMundo, siendo el método main el encargado de iniciar y terminar nuestro programa. Probablemente una de las formas más fácil de conocer la estructura de un programa en Java es generar uno. Para eso vamos a crear un pequeño ejemplo, que consista en un programa que nos permita ingresar el código de una asignatura, sus notas y luego nos entregue el promedio de ellas. La pregunta será entonces: ¿Qué datos nos permiten solucionar este problema? La conclusión será: El código de la asignatura, la sumatoria de las notas y la cantidad UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
131
de notas ingresadas para realizar la división en el cálculo del promedio. De forma tradicional estas variables hubiesen sido declaradas dentro del método main, sin embargo, esta vez no sólo crearemos un programa que nos permita realizar dicho cálculo, sino que definiremos en una clase como debe ser un objeto que permita realizar esta operación. La ventaja principal de esta solución, versus la anterior, es que a partir de esta clase podremos crear todos los objetos que queremos, incluso esta clase (nuestro plano del objeto) la podremos portar a otros programas que requieran realizar este cálculo.
Comenzaremos a confeccionar nuestra clase en un nuevo
archivo,
CalculadorDeNota.Java.
el Es
cual muy
llamaremos
importante
que
el
nombre del archivo coincida con el nombre de la clase que contendrá en su interior, adicionalmente debes recordar que las clases comienzan con mayúsculas y luego se escribe todo con minúsculas, salvo la primera letra de cada nueva palabra que contenga. El archivo CaluladorDeNota.Java debe lucir de la siguiente forma:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
132
Hasta aquí hemos definido una clase que permitirá crear un objeto de tipo CalculadorDeNota, sin embargo nuestro futuro objeto no contiene atributos ni comportamientos, o dicho de otra forma, nuestro objeto ya se puede construir (instanciar), pero no hace nada. Ha llegado el momento de
definir
en
nuestra
clase,
que
atributos
y
comportamientos se necesitan para resolver el problema. Como lo habíamos mencionado, se necesitará el código de una asignatura, la sumatoria de las notas y la cantidad de notas ingresadas para saber por cuanto hay que dividir. A estos datos los llamaremos atributos de una clase.
(Definición) Los atributos de una clase sirven para almacenar datos que son propios del objeto y se crean a partir de su instancia. Las variables declaradas como atributos no deben ir dentro de un método, ya que, debido al concepto de ámbito de una variable, sólo quedaría como una variable local del método, en cambio los
atributos,
deben
ser
vistos
por
todos
los
comportamientos que esta contenga. Para nuestro caso la clase y su respectiva declaración de atributos debe lucir de la siguiente forma:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
133
Ya que conocemos los atributos que nuestra clase tiene, ahora debemos enfocarnos en su funcionalidad, esta clase
consta
principalmente
de
3
métodos
o
comportamientos:
Sumar nota: el cual nos permite agregar una nueva nota, la que agregaremos a la sumatoria de las notas anteriores, adicionalmente debe contar la cantidad de notas sumadas al realizar la operación.
Resultado: divide la sumatoria de las notas en la cantidad de notas ingresadas.
Asignar asignatura: permite ingresar el código de la asignatura. Comenzaremos por el más sencillo, el comportamiento que calcula el resultado.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
134
Aquí se puede apreciar una importante ventaja con respecto al encapsulamiento que las clases poseen. Nota que se ha realizado el comportamiento resultado sin necesidad de tener el resto del código, este nivel modularidad permite llevar un mejor control sobre los errores. Agreguemos ahora el comportamiento que nos permite agregar una nueva nota.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
135
Con esto, nuestra clase ya se encuentra funcional y podemos realizamos
probarla ahora
desde una
nuestro
pequeña
método
main,
demostración,
es
importante que se comprenda que el código escrito en la clase no se ejecutará si no es llamado desde el método main, ya que mientras main no tenga la instrucción de construir un objeto, éste no lo hará.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
136
La
explicación
al
código
anterior
es
la
siguiente:
Declaramos un objeto de tipo CalculadorDeNota (de nuestra clase). Se crea un objeto CalculadorDeNota a partir de la clase y se almacena en el objeto calculador.
Asigna un código a nuestra calculadora
Agrega el número 50 y luego 40, al agregar cada uno de ellos es sumado con el resultado anterior, adicionalmente en la cantidad de notas es aumentada, para este caso tenemos: 0 + 50 +40 = 90; cantidadDeNotas = 2;
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
137
Imprime el valor que contiene la variable asignatura del objeto
calculador,
anteriormente.
es
Imprime
decir el
el
valor
001
ingresado
resultante
de
la
ejecución del comportamiento resultado.
Analicemos ahora el siguiente código:
En este caso hemos creado dos calculadoras con códigos de asignatura distintos, es importante mencionar que el beneficio que aquí se presenta es la posibilidad de crear dos objetos, donde cada uno de ellos posee sus propios atributos sin la necesidad de volver a codificarlos nuevamente. Fíjate que es incluso comprobable, ya que, UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
138
en el código anterior el objeto calculador y otroCalculador reciben en el nombre de la asignatura 001 y 002 respectivamente. Si miramos el resultado de las dos líneas que imprimen los valores de cada uno de los objetos creados, podría darte la impresión de que el resultado será “002” para ambos, debido debido a que has reescrito el valor de la variable asignatura, sin embargo dicho razonamiento, afortunadamente para nosotros es erróneo, siendo el resultado de la impresión 001 y luego 002 respectivamente. Esto comprueba de que cada objeto es distinto (concepto de identidad) y que las variables no son compartidas, sino que son propias de cada instancia.
Seguridad en una clase ¿Qué sucedería si decimos que todas los notas ingresadas al calculador de notas debe estar entre el valor 1 y 7? Nota que a los objetos instanciados a partir de la clase CalculadorDeNota se les puede forzar a dar un resultado que no tiene validez en el cálculo de las notas de una institución que utiliza la escala 1-7 que utilizamos en Chile, observe las siguientes formas en las que el código puede fallar.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
139
Como se puede ver, el valor entregado (-4564654) provocará que el cálculo final falle, de momento no parece algo tan difícil de solucionar, dado que no tiene sentido escribir como parte del código dicho valor, sin embargo, en un futuro no lejano, el código lucirá de la siguiente forma:
Esta variación permite que el valor entregado lo digite el usuario y es aquí cuando se presenta el mayor de los problemas, ya que es imposible adivinar qué valores digitará el usuario y es por ello que debemos prestar una especial atención en la forma de proteger nuestro software de las entradas de este tipo.
La solución más utilizada es la de crear el método get y set para cada atributo. Para proteger los atributos de nuestra clase, por ejemplo, en el programa que tenemos, podemos de forma sencilla asignar valores a sus atributos utilizando las siguientes líneas de código:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
140
El
valor
4
y
68
son
asignados
a
las
variables
cantidadNotas y sumatoria, ¿pero es eso correcto? Evidentemente no, ya que no existe ninguna posibilidad de que 4 notas sumen 68. El problema de seguridad ha sido causado debido a que ambos atributos son por defecto públicos, esto significa que sus valores pueden ser cambiados desde fuera de la propia clase, por ejemplo, en este caso el cambio lo genera el método main. Este problema tiene una solución bastante sencilla y consiste en proteger los atributos de forma que sólo la clase que los contiene los pueda cambiar, para ello es necesario cambiar su nivel de visibilidad (desde donde las variables son visibles y desde donde serán ocultas). Existen 3 niveles de visibilidad: • public: public: significa que los atributos de una clase pueden ser accedidas desde fuera de la propia clase. • private: private: significa que las variables sólo pueden ser utilizadas desde la misma clase. • protected: protected: permite a los atributos comportarse como privadas, pero públicas para las clases hijas de la clase que las declara. (se ve más adelante en el capítulo de herencia).
(Importante) en Java por definición todos los atributos de una clase deben ser privados.
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
141
Si dejamos de esta forma la declaración de variables de forma automática hemos ayudado a la seguridad, debido a que estas dos líneas de código ya no compilarán:
Sin embargo esto provoca un nuevo problema con la línea:
El error se produce debido a que ya no se puede obtener acceso ni de escritura ni lectura sobre la variable asignatura de ningún objeto de tipo CalculadorDeNota. Se preguntará ahora, si bien el problema de agregar notas con un valor inconsistente según la cantidad de notas ya ha sido solucionado, dado que la única forma de hacerlo es a través del comportamiento agregarNota, el cual mantiene una consistencia entre la suma de las notas y la cantidad de ellas, pero, ¿qué sucederá con la asignatura?
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
142
Get y Set. La respuesta a este problema se encuentra en el get y set de Java, los cuales no son otra cosa que dos comportamientos que existen por cada atributo que exista en la clase. Los get y set proveen un mecanismo que permiten cambiar o conocer el valor de un atributo desde fuera de la clase como si fuesen públicas, sin embargo agregan la posibilidad de llevar un mejor control sobre los valores que se le asignan. El comportamiento get (acceder) para el atributo asignatura lucirá de la siguiente forma:
Note, que nuestro get es un comportamiento muy sencillo de programar, su nivel de visibilidad es público, con ello conseguimos que sea visto desde otros lugares del código como por ejemplo, el método main, el tipo de retorno siempre es el mismo de la variable, en este caso es de tipo String y el nombre del comportamiento comienza con UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
143
get (obtener) y continua con el nombre de la variable que obtiene (getAsignatura), su firma no recibe parámetros y la única línea de código que posee el cuerpo del método corresponde a la devolución del valor de asignatura. El set en cambio es el comportamiento que nos permite cambiar el valor de nuestra asignatura:
El método set es todo lo contrario a get. Note que también es público, sin embargo no retorna ningún parámetro, dado que su objetivo es cambiar el valor del atributo asignatura, a cambio este método recibe como parámetro con un nuevo valor para la asignatura, el valor debe coincidir con el tipo de destino, finalmente dentro del cuerpo se asigna el nuevo valor a nuestro atributo. La siguiente línea de código tiene un papel fundamental en la asignación del nuevo valor:
Note que el método setAsignatura tiene dos variables llamadas
asignaturas,
una
corresponde
al
atributo
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
144
asignatura) y un parámetro con el mismo nombre, el objetivo final es recibir el valor en un parámetro para almacenarlo en nuestro atributo, pero cómo podría discernir Java si escribimos lo siguiente:
Pues de hecho sí lo hace, siempre que exista este tipo de situación la preferencia la tiene el parámetro que recibe el método, debido a que es una variable local del método que lo recibe, esto significa que la siguiente línea de código nunca asigna el nuevo valor al atributo, muy por el contrario sólo asigna al parámetro el valor que ya contiene, dejando al atributo intacto. Es aquí cuando la palabra reservada this marca la diferencia, debido a que ésta se utiliza para referenciar a todos los atributos o comportamientos que pertenezcan a la clase, por ende this.asignatura se refiere al atributo debido a que por medio de this no podemos llegar a variables locales de métodos u otros elementos que no se encuentren a nivel de clase.
Desde el método main, la utilización del objeto asignatura quedará de la siguiente forma:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
145
Existen diversos beneficios al utilizar este método, siendo uno de los más importantes la encapsulación de las validaciones que pueden aplicarse sobre los datos, por ejemplo, si necesitamos que la asignatura contenga tres caracteres, entonces debemos validar que la entrada del usuario nos entregue un String que cumpla con la condición de la siguiente forma:
Aquí se reciben los datos desde el usuario y luego se comprueba
que
la
variable
nuevaAsignatura
que
almacena el valor recibido cumpla con la condición de tener tres caracteres antes de ser entregada a la calculadora mediante setAsignatura. El problema que presenta esta validación es que tendremos repetirla por cada objeto que creemos, de la siguiente forma:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
146
El proceso de validación ha tenido que ser reiterado para cada
objeto
de
tipo
calculadorDeNota
que
existe,
simplifiquemos de manera significativa esto, utilizando la encapsulación y la ventaja que los mutadores nos proveen, en la clase CalculadorDeNota, modificamos el set para que luzca de la siguiente forma:
De esta forma la validación es parte del objeto y no será necesaria repetirla varias veces en el método main ya
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES
147
que se ejecutará cada vez que se ejecute la siguiente línea:
Es considerado una buena práctica crear el get y set para cada atributo de la clase. Si se desean mantener oculto el acceso a algunos de sus atributos deje el get y set del atributo con el modificador private, sin embargo, dentro de la misma clase aún podrá canalizar las validaciones en los set para realizar cambios en los valores de los atributos internos. De esta manera, la estructura de su código a partir de ahora debe lucir así:
UNIVERSIDAD TECNOLÓGICA DE CHILE INACAP - ÁREA INFORMÁTICA Y TELECOMUNICACIONES