Você está na página 1de 30
Figura 3.1 El visor de un relo} digital Principales conceptos que se abordan en este capitulo: @ abstraccion ™@ creacién de objetos @ llamadas a métodos ™ modularizacion mi _diagramas de objetos_m™ depuradores Construcciones Java que se abordan en este capitulo clases como tipos, operadores légicos (&&, | |), concatenacién de cadenas, operador médulo (%), construccién de objetos (new), llamadas a métodos (notacién de punto), palabra clave this En los capitulos anteriores hemos examinado qué son los objetos y cémo se los imple- menta; en particular, cuando analizamos las definiciones de las clases, hablamos sobre campos, constructores y métodos. Ahora, iremos un paso mas adelante, Para construir aplicaciones interesantes no es suficiente construir objetos que trabajan individualmente. En realidad, los objetos deben estar combinados de tal manera que cooperen entre ellos al llevar a cabo una tarea en comin, En este capitulo construiremos una pequeiia aplicacién a partir de tres objetos y trabajaremos con métodos que invocan a otros métodos para lograr su objetivo. EI ejemplo reloj El proyecto que usaremos para discutir sobre Ia interaccién de objetos modela un visor para un reloj digital. El visor muestra las horas y los minutos separados por dos puntos (Figura 3.1). Para este ejercicio, construiremos primeramente un reloj con un visor de 24 horas, de estilo europeo, por lo que muestra la hora desde las 00:00 (medianoche) hasta Jas 23:59 (un minuto antes de medianoche). Debido a que es un poco mis dificil de construir un reloj de 12 horas, dejaremos este modelo para el final de este capitulo. 58 | Capitulo 3. Interaccién de objetos Concept La abstracci6n es la habilidad de ignorar los detalles de las partes para centrar la atencién en un nivel mas alto de un problema. Abstraccion y modularizacion Una primera idea podria ser implementar totalmente el visor del reloj en una sola clase. Después de todo, esto es lo que hemos visto hasta ahora: cémo construir clases para hacer un trabajo. Sin embargo, abordaremos este problema de una manera un poco diferente. Veremos i podemos identificar en el problema, componentes que se puedan convertir en clases independientes; la razén de proceder asi radica en la complejidad del problema. A medida que avancemos en este libro, los ejemplos que usamos y los programas que construimos se volverin mas y mas complejos. Tareas triviales tales como la de la maquina de boletos pueden ser resueltas como si fueran un iinico problema: se puede ver la tarea completa y divisar una solucién usando una sola clase. En los problemas mas complejos, esta es una vision demasiado simplista. Cuando un problema se agranda, se vuelve més dificil mantener todos los detalles al mismo tiempo. La solucién que usamos para tratar el problema de la complejidad es la abstraccidn: dividimos el problema en subproblemas, luego en sub-subproblemas y asi sucesiva- mente, hasta que los problemas resultan suficientemente ficiles de tratar. Una vez que resolvemos uno de los subproblemas no pensamos mais sobre los detalles de esa parte, pero tratamos la solucién hallada como un bloque de construccién para nuestro siguiente problema, Esta técnica se conoce como la técnica del divide y reinards. Veamos todo lo dicho con un ejemplo. Imaginemos a los ingenieros de una fabrica de coches disefiando un nuevo coche. Pueden pensar en partes del coche tales como: su forma exterior, el tamaio y ubicacién del motor, el mimero y el tamaio de los asientos en la zona de los pasajeros, la cantidad exacta de espacio entre las ruedas, ete. Por otro lado, otro ingeniero (en realidad, este es un equipo de ingenieros pero lo simpli- ficamos un poco en funcidn del ejemplo), cuyo trabajo es diseftar el motor, piensa en las partes que componen un motor: los cilindros, el mecanismo de inyeccién, el car- burador, la electrénica, ete. Piensa en el motor no como una iinica entidad sino como un trabajo compuesto por varias partes, una de esas partes podria ser una bujia. Por lo tanto, hay un ingeniero (quizés en una fabrica diferente) que disefta las bujias. Piensa en las bujias como un artefacto compuesto por varias partes. Puede haber hecho estudios complejos para determinar exactamente la clase de metal que debe usar en los contactos 0 el tipo de material y el proceso de produccién a emplear para su aislamiento El mismo razonamiento es valido para muchas otras partes del coche. Un disefiador del nivel més alto pensar una rueda como una tni parte; otro ingeniero ubicado mucho mis abajo en la cadena de diseiio pasar sus dias pensando sobre la composicién quimica para producir el mejor material para construir los neumdticos. Para el ingeniero de los neumiaticos, el neumético es algo complejo. La fibrica de coches comprara los neumé- a una fabrica por lo que los vera como una tinica entidad y esto es la abstraccién, Por ejemplo, el ingeniero de la fabrica de coches hace abstraccién de los detalles de la fabricacién de los neumdticos para concentrarse en los detalles de la construccién de una rueda. El disefiador que se ocupa de la forma del coche se abstrae de los deta- Iles técnicos de las ruedas y del motor para concentrarse en el disefio del cuerpo del coche (se interesaré por el tamaiio del motor y de las ruedas). El mismo argumento es cierto para cualquier otro componente. Mientras que algunas personas se ocupan de disefiar el espacio interior del coche, otros trabajan en desa- rrollar el tejido que usarén para cubrir los asientos. Concepto La modularizacion €s el proceso de dividir un todo en partes bien definidas que pueden ser construidas y examinadas separadamente, las {que interactuan de maneras bien definidas 3.4 Modularizacién en el ejemplo relo) 59 El punto es: si miramos detalladamente un coche, esté compuesto de tantas partes que es imposible que una sola persona conozca todos los detalles de todas las partes al mismo tiempo. Si esto fuera necesario, jamais se hubiera construido un coche. La raz6n de que los coches se construyen exitosamente es que los ingenieros usan modu- larizacién y abstraccién: dividen el coche en médulos independientes (rueda, motor, asiento, caja de cambios, etc.) y asignan grupos de gente para trabajar en cada médulo por separado, Cuando construyen un médulo usan abstraccién: ven a ese médulo como un componente tinico que se utiliza para construir componentes ms complejos. La modularizacién y la abstraccién se complementan mutuamente. La modularizacién es el proceso de dividir cosas grandes (problemas) en partes mis pequeias, mientras que la abstraccién es la habilidad de ignorar los detalles para concentrarse en el cuadro mas grande. Abstraccion en software Los mismos principios de modularizacién y de abstraccién discutidos en la seccién ante- rior se aplican en el desarrollo de software, En el caso de programas complejos, para mantener una visién global del problema tratamos de identificar los componentes que podemos programar como entidades independientes, y luego intentamos utilizar esos componentes como si fueran partes simples sin tener en cuenta su complejidad interna. En programacién orientada a objetos, estos componentes y subcomponentes son objetos. Si estuviéramos tratando de construir un programa que modele un coche mediante un Jenguaje orientado a objetos, intentariamos hacer lo mismo que hacen los ingenieros: en lugar de implementar el coche en un nico objeto monolitico, primeramente pod amos construir objetos independientes para un motor, una caja de cambios, una rueda, un asiento, etc., y luego ensamblar el objeto coche a partir de esos objetos mas pequeiios. No siempre resulta facil identificar qué clases de objetos debe tener un sistema de soft- ‘ware que resuelve determinado problema. Ms adelante en este libro, tendremos mucho mas para decir sobre este tema, pero por el momento, comenzaremos con un ejemplo relativamente simple. Y ahora volvamos a nuestro reloj digital. Modularizacion en el ejemplo reloj Demos una mirada mas de cerca al ejemplo visor-del-reloj. Usando los conceptos de abstraccién de los que hemos hablado, simplemente queremos intentar encontrar la mejor manera de ver este ejemplo, para que podamos escribir algunas clases para imple- mentarlo, Una forma de verlo, es considerarlo como compuesto por un tinico visor con cuatro digitos (dos digitos para la hora y dos para los minutos). Si nos abstraemos nue- vamente de ese nivel tan bajo, podemos ver que también se podria considerar el visor como compuesto por dos visores de dos digitos: un visor de dos digitos para las horas y otro visor de dos digitos para los minutos. Un par de digitos comienza en cero, aumenta en uno cada hora y vuelve a ponerse en cero después de alcanzar su limite 23. El otro par de digitos se vuelve a poner en cero después de alcanzar su limite 59 La similitud del comportamiento de estos dos visores podria Hevarnos a abstraer nue- vamente y ver mas alli del visor de las horas y del visor de los minutos de manera independiente. Podriamos, en cambio, pensar en ellos como objetos que pueden mos- trar valores desde cero hasta un determinado limite. El valor puede ser incrementado, 60 Capitulo 3 Ml Interaccién de objetos Figura 3.2 El visor de un numero de dos digitos Codigo 3.1 Clase para el visor de un numero de dos digitos Concepto Las clases definen tipos. EI nombre de una clase puede ser vusado como el tipo de una variable. Las variables cuyo tipo es una clase pueden almacenar objetos de dicha clase, Cédigo 3.2 La clase VisorDeReloj contiene dos VisorDeNumeros pero si alcanza el limite vuelve al valor cero. Parece que hemos encontrado un nivel de abstraccién adecuado que nos permite representar la situacién mediante una sola clase: la clase del visor de dos digitos. Para nuestro visor del reloj programaremos primero una clase para representar un visor de un nimero de dos digitos (Figura 3.2); le pondremos un método de acceso para tomar su valor y dos métodos modificadores: uno para establecer el valor del limite y otro para incrementarlo Una vez que tengamos definida esta clase, podremos crear dos objetos de esta clase con diferentes limites para construir el visor del reloj completo. 03 Implementacion del visor del reloj Tal como lo mencionamos anteriormente, en vias de construir el visor del reloj cons- truiremos primero un visor que muestra un nimero de dos digitos. Este visor neces almacenar dos valores: uno es el limite hasta el que puede incrementarse el valor ant de volver a cero y el otro es el valor actual. Representaremos ambos en nuestra clase mediante campos enteros (Cédigo 3.1). public class VisorDeNumeros { private int limite; private int valor; Se omitieron los constructores y los métodos. } Mas adelante, veremos los restantes detalles de esta clase. Primero, asumimos que podemos construir la clase VisorDeNumeros y pensar un poco mas sobre el visor del reloj com pleto como un objeto que internamente esti compuesto por dos visores de niimeros (uno para las horas y otro para los minutos). Cada uno de estos visores de niimeros puede ser tun campo en el visor del reloj (Cédigo 3.2). Hacemos uso aqui de un detalle que no hemos mencionado antes: las clases definen tipos public class VisorDeReloj { private VisorDeNumeros horas; private VisorDeNumeros minutos; Se omitieron los constructores y los métodos. } Figura 3.3 Diagrama de objetos y diagrama de clases del VisorDeReloj Concepto El diagrama de clases muestra las clases de una aplicacién y las relaciones entre ‘lias, Da informacion sobre el cédigo. Representa la vista esatica de un programa, ‘Concepto El diagrama de ‘objetos musstra los objetos y sus relaciones en un momento dado de fa elecucion de una aplicacion. Da informacion sobre los abjetos en tiempo de ejecucion, Representa la vista dindmica de un programa. 3.6 Comparacién de diagramas de clases con diagramas de objetos 61 Cuando hablamos sobre los campos en el Capitulo 2, dijimos que la palabra «pri- vate» en la declaracién del campo va seguida de un tipo y de un nombre para dicho campo. En este caso en particular, usamos la clase VisorDeNumeros como el tipo de los campos de nombre horas y minutos, lo que muestra que los nombres de clase pueden usarse como tipos. El tipo de un campo especifica la naturaleza del valor que puede almacenarse en dicho campo. Si el tipo es una clase, el campo puede contener objetos de esa clase. Comparacio6n de diagramas de clases con diagramas de objetos La estructura que hemos descrito en las secciones anteriores (un objeto VisorDeReloj que contiene dos objetos VisorDeNumeros) puede visualizarse en un diagrama de objetos tal como se muestra en la Figura 3.3a, En este diagrama puede ver que estamos trabajando con tres objetos. La Figura 3.3b muestra el diagrama de clases de la misma situacién. a b) Observe que el diagrama de clases muestra solamente dos clases mientras que el dia- grama de objetos muestra tres objetos, cuestién que tiene que ver con el hecho de que podemos crear varios objetos de la misma clase. En este caso, creamos dos objetos VisorDeNumeros a partir de la clase VisorDeNumeros (Cédigo 3.3) Estos dos diagramas ofrecen vistas diferentes de la misma aplicacién. El diagrama de clases muestra una vista estatica, Representa lo que tenemos en el momento de escribir el programa: tenemos dos clases y Ia flecha indica que la clase VisorDeReloj hace uso de la clase VisorDeNumeros (esto quiere decir que la clase VisorDeNumeros es mencionada en el cédigo de la clase VisorDeRe1oj). También decimos que Visor- DeReloj depende de VisorDeNumeros. Para iniciar el programa, crearemos un objeto a partir de la clase VisorDeRe1oj. Noso- tros programaremos el visor del reloj de modo que cree autométicamente, en el mismo momento en que s¢ inicie el programa, dos objetos VisorDeNumeros. Por lo tanto, el diagrama de objetos muestra la situacién en tiempo de ejecucién (cuando Ia aplicacién se esti ejecutando); por este motivo, este diagrama se suele llamar vista dindmica 62 Capitulo 3 Ml Interaccién de objetos [Concepto Referencia a un objeto. Las variables de tipo objeto almacenan referencias a los objetos. Cédigo 3.3 Implementacion de ta clase VisorDeNumeros El diagrama de objetos también muestra otro detalle importante: cuando una variable almacena un objeto, éste no es almacenado directamente en la variable sino que en la variable s6lo se almacena una referencia al objeto. En el diagrama, la variable se muestra como una caja blanea y la referencia al objeto se muestra mediante una flecha El objeto al que se hace referencia se almacena fuera del objeto que hace la referencia, y la referencia al objeto enlaza la caja de la variable con la caja del objeto. Es muy importante comprender las diferencias entre estos dos diagramas y sus res- pectivas vistas. BlueJ muestra solamente la vista estitica: en la ventana principal se visualiza el diagrama de clases. Con la idea de planificar y comprender los programas Java, usted necesita poder construir diagramas de objetos en papel o en su mente, Cuando pensamos sobre qué hari nuestro programa, pensaremos sobre las estructuras de objetos que crean y cémo interactizan esos objetos. Es esencial comenzar a ser capaz de visualizar las estructuras de los objetos. yee * La clase VisorDeNumeros representa un visor digital de némeros que * puede mostrar valores desde cero hasta un determinado limite. * Se puede especificar el limite cuando se crea el visor. El rango de * valores va desde cero (inclusive) hasta el limite-1. Por ejemplo, * si se usa el visor para los segundos de un reloj digital, el limite * podria ser 60, y como resultado se mostrarén los valores desde 0 hasta 59. * Cuando se incrementa el valor, el visor vuelve automaticamente al * valor 0 al alcanzar el valor limite. * @author Michael K6lling and David J. Barnes * @version 2006.03.30 ey public class VisorDeNumeros a private int limite; private int valor; yee * Constructor de objetos de 1a clase VisorDeNumeros */ public VisorDeNumeros(int limiteMaximo) { limite = limiteMaximo; valor = 0; + jee * Devuelve el valor actual. rr Codigo 3.3 (continuacion) Implementacion e la clase VisorDeNumeros 3.6 Comparacién de diagramas de clases con diagramas de objetos 63 public int getValor() { + i * Configura el valor del visor con el nuevo valor especificado. Si el * nuevo valor es menor que cero o si se pasa del limite, no hace nada. return valor; ai public void setValor(int nuevoValor) { if((nuevoValor >= 0) && (nuevoValor < limite)) valor = nuevoValor; + ym * Devuelve el niimero del visor (es decir, el valor actual, como una * cadena de dos digitos. Si el valor es menor que 10, se completa con * un cero). i public String getValorDelVisor() { if(valor < 10) return "0" + valor; else return "* + valor; + i * Incrementa el valor del visor en uno, lo vuelve a cero si * alcanza el valor limite. ei; public void incrementar() { valor = (valor + 1) % limite; 7 Ejercicio 3.1 Piense nuevamente en el proyecto curso-de-laboratorio que hemos trabajado en los capitulos 1 y 2. Imagine que crea un objeto CursoDe- Laboratorio y tres objetos Estudiante y luego inscribe a los tres estudiantes en el curso. Intente dibujar un diagrama de clases y un diagrama de objetos para esta situacién. Identifique y explique las diferencias entre ellos. Ejercicio 3.2 {En qué momento puede cambiar un diagrama de clases? zCémo se cambia? Ejercicio 3.3 j£n qué momento puede cambiar un diagrama de objetos? eCémo se cambia?