Vale. Y bueno, dejaré un poco de tiempo porque siempre me he dado cuenta que cuando luego repasaba las grabaciones hay un pequeño retraso desde que pongo a grabar hasta que realmente se empieza a grabar. Entonces haré un poco de tiempo hasta que empezamos. Bueno, hoy tenemos un día realmente muy lleno de contenidos. No son muy difíciles y si habéis preparado un poco el trabajo nos costará mucho. Intentaré ir más o menos ligero. Pero la verdad es que si seguimos un poco el plan, la verdad hoy hay bastante material. Muy bien, pues vamos con esta segunda sesión de trabajo de la asignatura y vamos a ver un poco lo que había preparado para hoy. Antes que nada, antes de empezar, bueno, es un poco pronto, es verdad, pero podría ser que alguien hubiera tenido las primeras dudas. Por eso quería empezar preguntando si había dudas a los que están conectados. Bueno, lo hemos comentado un poco por el chat, pero si tenéis dudas no os cortéis en ningún momento de acudir al foro o plantearlas allí. Igual es un poco más fácil que contestarlas así en directo en webconferencia, pero bueno, si hay algo que en webconferencia se pueda resolver o en lo que voy a explicar e insistir más o menos, pues me iría bien saberlo. Va, lo que vamos a explicar hoy tiene... Va, lo que vamos a explicar hoy tiene dos apartados. Hablaremos de cómo se definen las clases en Java y una segunda parte en la que hablaremos de cómo se trabaja con objetos. O sea, sabéis que las clases son la definición genérica y los objetos son la definición concreta cuando el programa está funcionando. De eso hablaremos hoy. Ahora he estado viendo si podía hacer el experimento de compartir el escritorio. Y para este experimento... Eh... Para el ejercicio que os quería plantear ahora, me iría muy bien poder utilizar lo del escritorio. Sé que cuando conecte esto, lo he estado probando y funciona, lo que pasa es que imprime un cierto retardo entre el audio y el vídeo. Si estáis en directo no sé, pero en diferido provoca esto. Entonces, os sugiero una cosa. Como ya tenemos la práctica, he basado los comentarios en un... En una supuesta definición de una clase componente. Da igual la clase que vosotros defináis, pero en BlueJ, si queréis hacer este experimento, lo que podríais hacer es creáis una clase y por defecto sabéis que BlueJ os construye una clase con un contenido básico y con un método elemental. Bueno, pues con esta misma clase podemos hacer estos experimentos. La idea es que desde BlueJ... Desde... Hagáis clic sobre la definición de la clase y se desplegará un menú que dice new lo que sea, el nombre de la clase. En este caso, si definía una clase componente, aparecería un new componente y cree varios objetos. Cada vez que pincháis a new componente o new objeto el que sea, se abre una ventana en la que pide confirmación para darle un nombre a este objeto. Los objetos... La clase tiene un nombre, pero cada vez que tú creas un objeto... Lo vas a referenciar con un nombre particular. Y puedes crear tantos como quieras. Estos objetos aparecerán en la parte inferior, lo que se llama el banco de objetos, en color rojo, identificados con este nombre. Sabéis, si habéis leído el enunciado de la práctica, que ya tenemos lista a nuestra disposición, nos piden que hagamos, como primera fase, la definición de un objeto de una clase componente en la que... Nos piden que tenga una serie de atributos, como son el precio de venta, el código, el código del fabricante, el nombre del fabricante, una descripción, una serie de atributos. Y luego nos piden que para cada uno de esos atributos creemos métodos para asignarlos y consultarlos. ¿De acuerdo? Es un poco recapitulando lo que piden en la primera parte. Es una primera parte realmente muy mecánica. Se puede hacer en... Nada, 15 minutos. Tan mecánica que a veces es un poco tediosa copiar y pegar para hacer un método, leer y consultar cada uno de los atributos. Pero desde luego es una práctica que se... Una primera parte se resuelve muy, muy rápido. Entonces, si podéis jugar con el entorno este, os podríais plantear estas preguntas. ¿Cómo se establece el precio de un objeto de la clase componente? Bueno. Bueno, si habéis entendido un poco el concepto de lo que se nos pide, es que el precio no lo voy a establecer directamente. Lo que voy a hacer es, a un objeto en concreto, voy a invocar un método que permite modificar el precio. ¿Vale? O sea, la respuesta es, a través de un método, setPrecio o algo parecido. Esta sería la respuesta a la primera pregunta. ¿Vale? Por supuesto, si creáis un objeto para hacer experimentos, pues tiene que tener este método definido. Si no, no. Veremos más adelante cómo podemos hacerlo. Pero, visto desde fuera, si alguien me da ya el objeto componente hecho, yo podría interactuar. Por eso he titulado esta primera parte vista externa, sin saber los detalles. Es decir, si ya me lo dan hecho, yo podría jugar con componentes, utilizando sus métodos, ignorando completamente cómo está hecho por dentro. Luego pide, ¿cómo recuerda un componente el nombre de su fabricante? Esto sí que es un detalle un poco más interno. Porque, realmente, la forma de recordar el nombre de un fabricante o cualquier otra de sus cosas forma parte de su estado. Y cómo un objeto guarda información de su estado. A través de los valores que guarda en sus atributos. Esta sería la conclusión. Bueno. Continuemos. La siguiente cuestión. Lo mismo casi. ¿Cómo accedemos al nombre del fabricante de un componente? Tampoco directamente, sino a través de un método que nos permite extraer el nombre del componente. ¿Cómo accedemos al nombre del fabricante de un objeto en concreto? Todas estas pruebas las podéis ejecutar directamente desde el entorno de BlueJ. Pero tened en mente que este entorno de pruebas y juegos es un entorno meramente educativo. Lo que nos van a pedir en la práctica es que hagamos un programa principal desde el que podamos hacer esto mismo. Crear componentes, meterle valores llamando a métodos y consultar valores llamando a métodos. Al final de la presentación de hoy os mostraré un pequeño ejemplo de programa principal. Y no sé por qué esperará luego. Podemos ir directamente a enseñaros un poco este programa principal. Lo había previsto al final porque también tiene sentido al final. Pero os lo voy a mostrar ahora. Un ejemplo de programa principal en el que yo haría uso de un objeto componente previamente creado sería algo así. No es esta diapositiva. Es dos más atrás si no me equivoco. O tres. O cuatro. No, no puede ser tan lejos. Disculpad un momento. Ahora la localizo. Vaya pues o he subido una versión obsoleta. Ahora estoy preocupado. Ah, no. Aquí está. Afortunadamente. En la cabeza me constaba que estaba en otro sitio pero no, no. Es esta. Bueno. Esto sería... A ver si... La calidad no es muy buena pero creo que podremos entendernos. Esto sería... Bueno, aquí hay unos pequeños comentarios. Aquí he creado una clase que la llamo lanzador. Esto forma parte también de la etapa uno, que creemos una clase lanzador. Que tiene un único método un poco especial. Este método se tiene que escribir exactamente así. Lo vimos también en la sesión anterior. ¿Y qué hacemos aquí dentro? Bueno. Como yo tengo fuera, en el mismo proyecto, definido... Definido un objeto, una clase componente. En mi aplicación puedo crear dos variables c1 y c2 de la clase componente. Pero esto todavía no son componentes. Estos son simplemente dos variables capaces de referenciar un componente. Los componentes los creo con estas dos instrucciones que vienen a continuación. Esto es lo que los construye. Esto es lo que digamos reserva memoria para almacenar estos dos objetos. A partir de aquí, sí que ya tengo dos objetos. Cada uno vinculado a las variables c1 y c2. Y a través de estas variables puedo hacer referencia a sus métodos. Utilizando cosas como setCódigo, setDescripción, setPrecioDeVenta, setCódigoDeFabricante. Los he llamado de forma secuencial o así un poco uniforme. Los he llamado set porque son métodos que establecen cosas. Los podéis llamar como os dé la gana. Pero bueno, los he llamado así un poco insistiendo en una nomenclatura un poco uniformizada. ¿Qué estoy haciendo aquí? Estoy accediendo a propiedades de dos objetos de los que supuestamente sé que tienen estas instrucciones que permiten manejarlos. Y me estoy comunicando con ellos. Esto sería lo mismo que podría estar haciendo a través de BlueJota. Jugando, haciendo clic sobre las clases y creando objetos. Y después haciendo clic sobre los objetos y llamando a las funciones manualmente. Esto sería como lo haría en el programa principal. Si os fijáis estoy definiendo los atributos de dos objetos c1 y c2. El c1 es una placa base y el c2 es una tarjeta gráfica. Este sería un poco el ejemplo de cómo se ve un objeto desde fuera. Desde fuera desde el banco de objetos o desde fuera desde el programa principal. Muy bien, pues retomemos donde estábamos. Esto sería ver el objeto desde fuera. ¿Qué es lo que vemos cuando accedemos al código? A ver internamente cómo está codificado un objeto. Bueno, vamos a tener una visión interior, una visión de desarrollador, una visión de las tripas del objeto. Nosotros lo que acabo de decir es que podemos interactuar con estos objetos mediante sus métodos sin conocer sus detalles internos. Lo que sí vemos si vemos el código es los detalles de cómo se implementa el comportamiento de estos métodos set, get y otros que vamos a ir haciendo. Ahora vamos a describir cómo es la estructura general para hacer una clase y veréis que en Java todas las clases siguen el mismo esquema. No hay más que eso. Hay algunos otros detalles, pero toda clase de Java tiene un esquema similar. Antes de enseñar un poco este esquema, un pequeño comentario. La primera instrucción en Java, la más básica que vamos a conocer y el otro día ya presentamos, porque es inevitable para hacer un programa, es casi imposible, es asignar el valor a una variable. Se llaman sentencias de asignación. Y como ya sabéis es algo tan sencillo como referirte a una variable, utilizar el símbolo igual y a la derecha poner una expresión. Claro, esta expresión tiene que ser compatible con el tipo de la variable que hay a su izquierda. O sea, no puedes intentar almacenar un carácter sobre una variable. Esto es tipo, quería escribir. Casi parece que dice todo, pero bueno, tipo. ¿De acuerdo? Si aquí tengo una variable de tipo entero, a la derecha tengo que tener una expresión que resulte en un número entero. O un número o un cálculo o lo que sea. Tened en cuenta que una variable no recuerda, simplemente almacena un solo valor. Por tanto, si previamente tenía alguna otra cosa, ese valor es olvidado. Se pierde inmediatamente. Bueno, pues ahora sí, vamos a la estructura básica de cómo es una clase. Todas las clases que vamos a hacer nosotros, tal vez habrá alguna un poco diferente, pero esto es el 99% de las que vamos a hacer, van a ser de este tipo. Public, class y el nombre que le vamos a dar a la clase, sea la que sea. Voy a cambiar de color. Esto, esta parte de aquí, es lo que se llama, bueno, envoltorio es una forma poco rigurosa de llamarlo. Pero ya me entendéis, es un poco la cabecera, el encabezado. Esta parte que va entre las llaves, sería el cuerpo de la definición de la clase. Y aquí dentro, vamos a ir definiendo atributos, constructores y métodos. Ahora vamos a ver un poco más en detalle cada una de estas piezas. De constructores apenas hemos hablado. Si hemos hablado ha sido un poco de pasado intentando evitar dar muchos detalles. Pero ahora vamos a desgranarlos poco a poco. Los atributos. Ya hemos hablado de ellos, vamos a profundizar un poco. Estamos hablando que los atributos lo que hacen es almacenar los valores que definen el estado de un objeto. También reciben el nombre de variables de instancia, porque no son más que variables. Al fin y al cabo son un tipo especial de variables. Uy, aquí se me ha colado un comentario de la transparencia original. Estoy haciendo un poco unas versiones de unas transparencias que... tengo a mi disposición en inglés y se me ha colado este comentario. Esto es una de las cosas que podéis hacer con el inspector de objetos. Cuando tienes un objeto hay una función inspect para verle las tripas y ver los valores. Entonces, si queréis jugar desde el banco de objetos, desde BlueJ, podéis utilizar esta función inspect. Ya hemos dicho, el conjunto de atributos y sus valores definen el estado de un objeto. Y en general, los atributos siempre van a estar... o sea, los calificaremos como privados y van a estar ocultos. Es decir, jamás accederemos directamente desde fuera del objeto a modificar un valor directamente. Siempre lo haremos utilizando métodos. Eso se podría... digamos que estrictamente Java no lo garantiza. Tú podrías saltarte esta regla. Pero nosotros lo vamos a utilizar como si fuera una regla inviolable y de oro. Tiene grandes ventajas, las iré presentando. Y es por eso que estos atributos de la clase componente los marcamos con este inicio que dice private. O sea, regla entre nosotros universal va a ser definir todos los atributos empezando con la palabra private. Después viene el tipo y después el nombre del atributo. Siguiendo este esquema. ¿De acuerdo? Solo un pequeño comentario. ¿Por qué lo hacemos así, privado, y no los hacemos de otra forma? Existe el modificador public y los tocamos directamente y tengo que pasar por un método. Realmente, el método me garantiza que ese atributo se modifica de forma coherente con el comportamiento que debe tener el objeto. Si yo dejo que los componentes de un objeto se puedan modificar con total libertad... ...podría poner el objeto en un estado que no representa nada para, digamos, para mi problema. Por ejemplo, podría tener un objeto componente al que no le he puesto código de fabricante ni código. ¿Por qué? Pues porque directamente le he borrado el código. En cambio, si el manejo de código está controlado por un método que es la única forma de acceder a él... ...puedo imponer restricciones a cómo voy a usar este atributo. Es decir, los métodos garantizan que el objeto se va a comportar y va a estar siempre en un estado que tiene sentido para mí. Esta es la importancia de los métodos. Los métodos sí que serán públicos. Desde fuera yo podré llamar estos métodos que serán los encargados de tocar estos atributos privados. Este es un esquema que vamos a respetar en nuestra práctica y que en general es una muy buena práctica. Puede ser que en algún caso haya alguna excepción a hacer a esta norma, pero en general considerarlo como un principio muy recomendable... ...hacer siempre este tipo de diseño. Atributos privados, métodos públicos. Vayamos a los métodos y acá hablábamos de ellos. Lo que hacen es implementar el comportamiento de un objeto y los podemos ver como una cabecera y un cuerpo. En la cabecera tenemos también para el método la definición de su ámbito. Esto se llama el modificador de ámbito o de visibilidad. O simplemente el ámbito o la visibilidad. Fijaos que para un ejemplo de método le he marcado como público. Este sería un método, obtenerPrecio, que sobre un objeto componente, supuestamente si este método pertenece a los objetos de la clase componente... ...este método está pensado para que desde fuera sea accedido con total naturalidad. Por tanto lo he marcado como público. En este caso precede al nombre del método un tipo. Esto es lo que se llama el tipo de retorno. Y explicaremos un poco más adelante este tipo de retorno, qué es y por qué puede ser void. Void significa vacío, es decir, no devolver nada. A continuación, forzosamente como mínimo habrá un paréntesis abierto y un paréntesis cerrado. Porque aquí en medio está la opción, si el método lo necesita, de añadir una lista de parámetros. En este ejemplo, obtenerPrecio es un método que no necesita parámetros... ...pero si fueran necesarios irían aquí. El cuerpo del objeto va encerrado entre una llave abierta y una llave cerrada... ...y es donde se contienen las instrucciones, las sentencias en Java que definen el comportamiento de este objeto. Vaya raya. Bueno, pasemos a la siguiente. Cuando un método necesita parámetros, es lo que decía antes, van después en estas llaves. Aquí hay otro ejemplo de método un poco distinto. Un poco distinto en algunas cosas. Public se mantiene igual, pero en este caso es un método que no necesita devolver nada... ...y por eso este método empieza con la palabra void. Si este método tuviera que informar al mundo exterior con un texto, con un número o con lo que sea... ...llevaría aquí un tipo. Pero, como es un método mudo, por decirlo de alguna forma, cuando los métodos son mudos los marcamos como void. Aquí tenemos el código del fabricante, como nombre del método, setCodeFabricante. ¿Y qué pasa si necesito más de un parámetro? Ningún problema. Separo las declaraciones de parámetros necesarios, si necesito dos, tres, cuatro para este método, separados por coma. Es decir, aquí podría venir coma, otro tipo y otro nombre de parámetro. Coma, otro tipo y otro nombre de parámetro. Todos los que necesitas. Este es el caso de un atributo que se encarga de establecer el código del fabricante de un componente. ¿Y cómo funciona? Algo tan sencillo como asignar al atributo código del fabricante, esto es una asignación... ...el valor que se recibe por parámetro. ¿De acuerdo? Este P fabricante, esta p minúscula, sugiere... ...es un convenio también. Fijaos que aquí he puesto añadir una p delante del nombre de un parámetro es una cuestión de estilo y de claridad. Vale, pues con esto sé que si respeto mi propio código las variables dentro de mi método que se llamen p minúscula, empezando por p minúscula... ...van a ser parámetros que he recibido, digamos, desde fuera como valores añadidos al método. ¿Vale? Bueno, pues un método para establecer el código del fabricante es algo tan sencillo como al atributo le asigno el valor que me llega por el parámetro. Nada más. Esto sería un típico y básico ejemplo de set. ¿Qué vais a hacer en vuestra práctica? Pues uno de estos métodos por cada uno de los cinco o seis atributos que nos piden para la clase componente. O sea, algo tan sencillo como eso. ¿Vale? ¿Podría llamar yo al parámetro exactamente igual, codfabricante? Pues sí, podría llamarlo. Pero aquí fijaos que se daría una situación extraña. Tendría a la izquierda codfabricante y a la derecha exactamente igual, codfabricante. Eso plantearía un problema, eso daría un error. Si sucede eso... ...si quiero referirme al atributo... ...y hay una coincidencia entre el nombre del parámetro y el nombre del atributo... ...deberíais utilizar esto, this. Y el nombre del atributo para romper esta ambigüedad. Porque si tenéis un parámetro que justamente coincide con el nombre de un atributo vais a tener un conflicto de nombres. ¿Vale? Entonces mi recomendación es no creéis parámetros con los mismos nombres que atributos. Y una forma sencilla y además elegante es añadir una p minúscula delante. Este es un poco un truco. Bueno, no es un truco, es una cuestión de estilo y claridad. Todas estas pequeñas cosas de estilo y claridad... ...suficientemente complicada es... ...complicado es mantener el orden y entender un código... ...da igual si lo has hecho tú o lo ha hecho otro... ...que uno busca hacer todas estas pequeñas modificaciones de estilo que puedan... ...facilitarte el trabajo. Un comentario de pasado, no lo he mencionado explícitamente... ...pero los nombres de variables y los nombres de métodos son sensibles a mayúsculas y minúsculas. Es decir, si tu método se llama set empezando por una s minúscula... ...lo cual también es una práctica de estilo conveniente. Hay un apéndice, creo que es el apéndice j en el que os da unas indicaciones de estilo en el libro de referencia. Apéndice j. Veréis una serie de recomendaciones de este tipo. ¿Cómo conviene llamar a los métodos y a las variables? Convenios generales que la mayor parte de los programadores de Java respetan... ...porque se sabe que ayudan. Hay uno de ellos que dice, va, los nombres de los métodos siempre en minúscula... ...y los nombres de las clases que empiecen siempre por mayúscula. Vale, bueno, es un pequeño convenio. Lo que quiero decir también es que si tengo un método que empieza así... ...si llamo a otro método rompiendo esta regla y lo llamo set empezando con mayúscula, etc. Java lo considera completamente distinto. O sea, una diferencia en una letra cambiarle de mayúscula a minúscula es significativo para Java. Si intentáis referiros a un método haciendo esto y lo habéis definido de otra forma no lo encontrará, os dará un error. Muy bien. Hablemos de un tipo especial de métodos. Cuando defines una clase es obligatorio definir al menos un constructor. ¿Qué es un constructor? Bueno, no es más que un método. Es un método un poco especial. ¿Qué tiene de especial? Bueno, pues que el nombre no lo invento, sino que el nombre tiene que ser coincidente exactamente con el nombre de la clase. El mismo nombre que su clase. Es decir, mi clase componente en mayúsculas tendrá un método componente en mayúsculas. Esto es un constructor. Tienen una particularidad que es que no llevan tipo. O sea, así como el resto de los métodos aquí llevan o void o un tipo, el tipo de retorno, los constructores no llevan tipo. Ojo con esto. Y la lista de parámetros, pues opcional. Pueden no llevar parámetros o pueden sí llevarlos. Típicamente llevan, pero no es obligatorio. ¿Y qué hace un constructor? Bueno, un constructor se ejecuta automáticamente. Nadie lo llama. Cuando tú creas un objeto, este trozo de código se ejecuta siempre para todos los objetos que tú crees de esta clase. ¿Qué quiere decir? Que aquí se ha previsto que cada vez que tú quieras crear un componente le tienes que dar un código. ¿De acuerdo? El constructor exige un código de tipo entero. ¿Y qué hace con este código? Bueno, pues lo guarda en el atributo interno código y el precio de venta al público automáticamente lo pone a cero. Esto es un ejemplo nada más. No es que vuestros componentes tengan que tener este código. Pero os quiero decir que los atributos de un objeto recién creado, tú puedes hacer lo que te plazca con ello. Los puedes poner todos a cero. Si son strings, ponerlos a un valor predeterminado. O puedes darle todo. Todos los valores que tú necesitas para inicializarlos como parámetros. Y entonces aquí hacer una batería de asignaciones con los valores que te llegan por parámetro al construir un objeto. Veremos más ejemplos. Pero un constructor sirve para eso, para inicializar el objeto. Y típicamente lo que hacen es esto. Almacenar los valores de los parámetros en los atributos. Pero pueden hacer cosas mucho más complejas. Pueden hacer un montón, todo lo que tú quieras. De hecho, en este cuerpo tú puedes hacer lo que te plazca. Bueno, que tenga sentido, por supuesto. Pero puedes hacer todas las operaciones que el lenguaje Java te permite. Una particularidad que veremos también y no es nada extraño es que en una clase haya varios constructores. Lo que tiene que pasar es que tengan parámetros diferentes, eso sí. No puedes tener dos componentes exactamente con este mismo esquema. O sea, yo no podría tener más abajo otro public . Eso no puede ser. ¿Por qué? Pues porque los parámetros tienen que diferenciarse en algo. Tienen que ser distintos. ¿Y qué va a suceder? Pues que si yo llamo a un constructor con un determinado conjunto de parámetros, se ejecutará un cierto código. Si tengo otro constructor que cuando, por ejemplo, en lugar de recibir pCódigo, tengo otro constructor que recibe código y precio, bueno, pues se ejecutará este otro si lo llamo con dos parámetros. Este comportamiento de tener más de un método, en este caso un método constructor con el mismo nombre pero con diferentes parámetros es lo que se llama sobrecarga. Yo sobrecargo de significado la palabra componente atribuyéndole más de un comportamiento. Volveremos sobre esta palabra después. En cualquier momento, los que nos estáis siguiendo en directo, si queréis plantear una consulta en el chat, yo estaré atento. Adelante. Igual los que estáis en Mallorca, en la sala de Palma. Si estáis en la sala de informática, os podéis conectar a webconferencia desde el ordenador del alumno cada uno. O bien ir a la mesa del profesor y teclear desde allí. Pero quiero decir, si queréis tener conexión personal y escribir directamente desde vuestra mesa o desde vuestro ordenador portátil si tenéis conexión, no... No os cortéis de hacer preguntas. A mí me servirá saber en qué insistir y en qué no. Ah, vale. Estás solo en Mallorca. Vale, perfecto. Y además ya veo, estás en la sala y estás conectado con tu usuario. Perfecto. Bien. Bien hecho. Vale. Bueno. Cuando nos referimos a métodos GET y SET. Es una pura formalidad. No es que tengan nada especial. Sino simplemente es que los métodos llamados GET. Son los métodos que consultan valores de los atributos. ¿Vale? Típicamente tienen esta forma. Bueno, el modificador de visibilidad. Ya sabemos. El cuerpo. ¿Vale? Tienen un tipo de retorno. Esto sí que no sería normal. Concebir un método que consulta algo y no tenga un tipo de retorno. Que aquí tuviera un void raro para un método que consulta. Un nombre. Y muchas veces la lista de parámetros está vacía. Porque si simplemente es consultar el valor de un atributo. No necesitará más información. Pero esto no siempre es cierto. Podría no estar vacía. Lo que sí es importante es que si hay un tipo de retorno. Tiene que haber un return al menos. La sentencia return lo que hace es, al final del código. Darle sentido a este tipo de retorno. Es decir, pone algo como respuesta de este método. En este caso. Este es un método GET súper simple. Que lo único que hace es devolver el precio de venta del objeto componente en cuestión. Lo mismo que antes. Hemos visto un método SET. Pues métodos como este. Tenéis que hacer cuatro o cinco en la primera parte de la práctica. Tan sencillo como esto. O sea, yo he hecho así rápido la primera etapa de la práctica. Y simplemente he hecho cinco métodos GET y cinco métodos SET. Y ya está. Esto sería. Un método SET tiene una estructura similar. En principio pensados para modificar el estado de un objeto. Pueden modificar uno o más atributos. Y típicamente contienen sentencias de asignación. Normalmente, claro, recibirán parámetros. Si van a cambiar algo. Bien pueden cambiarlo con un cálculo sobre el estado del sistema. Pero típicamente recibirían parámetros. Aquí os he puesto un ejemplo con dos parámetros. Esto ya no pertenece a la clase COMPONENTE. He buscado otro ejemplo. Imaginaos que estamos modelando un cajero automático. Y esto es un método de la clase CAJERO AUTOMÁTICO. Y tengo un método RETIRARFONDOS del cajero. Suponed que este método requiere que le pase una cantidad. Que tiene que ser un número entero. Porque no puedo sacar céntimos. Tengo que pasarle una cierta cantidad. Y además a este método tengo que pasarle, esto sí, una comisión a aplicar. Le he puesto de tipo DOUBLE. Porque esta comisión sí que va a tener decimales. Bueno, pues la operación podría ser algo como esto. Al atributo SALDO lo cambio con el valor antiguo de saldo. Este es el valor anterior antes de hacer la modificación. Restándole la cantidad y restándole la comisión. Este método SET sí que no tiene ninguna sentencia RETURN. Porque aquí tiene un VOID. No tiene que hacer ninguna modificación. Perdón. Hace una modificación pero no tiene que devolver nada al mundo exterior. Por tanto, VOID aquí y no tiene ningún RETURN. Esto sería un SET más o menos típico. Pero luego ¿qué va a pasar? Que tendréis métodos que no serán ni puramente SET ni GET sino una mezcla. Por supuesto podéis tener todas las combinaciones posibles que os imaginéis intermedias. Métodos que calculan la información parcialmente. Y otras cosas las sacan de parámetros. Otras cosas las sacan preguntando a otros objetos. En fin. Estos son las dos formas de métodos más elementales. Pero desarrollaremos los que necesitemos en cada caso. Esta creo que está repetida. Para no estar tan pasivos os propongo un pequeño ejercicio, un juego. Si no es un rollo me aburro hasta mí de escucharme. Aquí tenéis un pedacito de código de la definición de una clase llamada máquina de chicles. O máquina de chicles. Os garantizo que hay cinco errores. A ver quién los encuentra. Os doy unos instantes a ver si localizáis cinco errores en este código. En principio esta es la declaración de una clase. Yo mientras voy hablando vais pensando. Si me queréis hacer alguna aportación me la decís y si no lo revelo después. Esta entidadía es la definición de un atributo. Y tenéis dos métodos. Este método. Hay. Perdonad. Aquí hay un error no intencional. Esto de aquí no lo consideréis un error. Esto debería decir máquina de chicles. Máquina de chicles. Luego lo corregiré en las diapositivas que os colgaré. ¿Vale entendido? Esto ha sido un error de traducción, de transcripción mío. Esto debería decir máquina de chicles. Que simplemente cuando construye una máquina de chicles le asigna al precio un valor fijo de 0.5. Esto es una posibilidad. Es decir, cada vez que tú creas una máquina de chicles el precio va a piñón. No entra por parámetro. Esto es una de las cosas que puede hacer un constructor. Y luego tiene un método getPrecio. A ver, fallos que veáis aquí. Tenéis que empezar a acostumbraros a que Java no os va a perdonar ni una coma ni un punto. Es decir, va a ser muy estricto. Entonces, ¿alguna aportación? ¿Veis algún fallo? Ya os digo, hay cinco. Al final cuando os los muestre diréis. Ah, es verdad, pero cómo se me ha escapado. Bueno, hay que acostumbrarse. Correcto. Ya hay algunas aportaciones. El último precio tiene que ir en minúsculas. Correctísimo. ¿Qué pasa si precio lo refiero aquí en mayúsculas? Yo he definido el atributo en minúscula. ¿Vale? Aquí precio está en minúscula. Quiero utilizar el rojo. Y aquí lo refiero en mayúsculas. Error. Esto es un error. Sí señor. Muy bien. Otro error que veo por ahí. Private falta tipo de precio. Correcto. Este es otro fallo. Aquí dice private. Un atributo sí, correcto. Tiene que ser private. Pero aquí hay que decir de qué tipo. Correcto. Muy bien. Por tanto, aquí como tiene que ser un número decimal, podríais utilizar o bien un float o bien un double. En principio yo optaré por double. Después veréis por qué. Pero bueno, es un detalle. Double simplemente es un número con más precisión que los float. En el apéndice creo que es B. Describe exactamente las precisiones a las que llegan. Y ¿hay algún detalle más? Ya tenemos uno, dos fallos. Sí, sí señor. Un punto y coma. Aquí hay un punto y coma. Y alguno más. Quedan dos. Ya tenemos tres. Hay uno un poco malicioso. Hay uno que la verdad es que a mí también se me habría pasado fácilmente. Está claro. Vale. Pues os lo desvelo. Aquí jamás acabaréis un método así. Como mínimo, si no necesita parámetros, vais a poner un paréntesis, paréntesis. Y aquí hay otro fallo. Y es que el cuerpo de la clase empieza con una llave pero necesita su correspondiente llave final. Aquí no hay una llave final. Necesitamos una llave aquí cerrada. ¿De acuerdo? Este ejercicio está bien. Es un simple ejercicio de observación. Pero ¿qué va a pasar cuando codifiquéis os pasará esto? Vais a poder estar peleando con un error tonto de un simple despiste. Acostumbraos a leer lo que os dice el compilador. A veces ayuda y a veces ayuda de forma menos evidente. Pero quiero decir, acostumbraos a qué os va a pasar esto. No es nada grave. Bueno, he saltado a otra presentación por accidente. Ahora volvemos. Muy bien. Ahí están los errores marcados para si después consultáis esto. Bueno, siguiente cosa que querría comentar. Cuando manejamos variables de tipo string, nosotros las podemos concatenar. Es decir, a partir de fragmentos podemos hacer strings más largos. Por ejemplo, el ejemplo 2 es un ejemplo. Un string literal, o sea, definido como literalmente, se marca entre comillas dobles. Y si yo utilizo el símbolo más, es el operador para hacer concatenación de strings. Esto produciría un string combinado de este estilo, 3. Pero todos sabemos que el símbolo más también funciona como el operador de suma de enteros y de números decimales. Vale. Esto nos da algunas situaciones curiosas que ahora analizaremos. Pero, en general, tened en cuenta que, aparte del sentido de sumar números, el más lo podéis utilizar para concatenar strings. Con la particularidad de que, si yo tengo un string y un número, aquí podría tener un número 6 o una variable llamada num de tipo int. Bueno, pues también se produce una concatenación. Ya va por supuesto que si yo intento concatenar un texto con un número es que quiero producir una salida combinada de este estilo. Vale. Pues, ojo, en este caso, aunque yo sume una cadena con un número, me va a dar una cadena. No va a dar error. Él hace esta presuposición. Y aquí tenemos un ejemplo típico de formateo de este estilo. Un simbolito delante concatenado con una variable de tipo número y con un texto con la moneda euros. Produciría una salida de este estilo. Aquí tenemos otra vez un ejemplo de sobrecarga. Lo que pasa es que en este caso, la sobrecarga la vemos aplicada a un operador. Realmente un operador no es más que una forma un poco extraña de definir un método. Al fin y al cabo, es un método. Yo podría pensar en el operador suma como un método de este estilo. Más, paréntesis, valor 1 coma valor 2. Valor 2. O sea, un operador que recibe dos parámetros y produce un resultado. Vale. Pues, si lo entendéis de esta forma, lo que sucede en este caso es que el operador suma está sobrecargado. Realmente, cuando yo le paso dos números al operador suma, funciona de una manera. Y cuando le paso como primer parámetro una cadena y como segundo o bien otra cadena o bien un número, funciona de otra. Hace una concatenación. ¿De acuerdo? Vale, pues es otro ejemplo de sobrecarga. Y eso pasa con los constructores, con los operadores y con cualquier otro método. En general, sobrecarga tendría esta definición. Consiste en tener más de un método con el mismo nombre, de manera que llamaremos a uno u otro según los parámetros que le mandemos. Cosas que hay que tener en cuenta. Bueno, esta instrucción no sé si la habéis visto haciendo algún experimento en la instrucción que muestra algo por pantalla. System.println Es un poco largo escribir, pero bueno, tiene su porqué. Este es el nombre del paquete en el que está una función al fin que se llama println. Vale. Si yo construyo una cadena utilizando el operador más así, ojo que el operador ve un número, ve el más y otro número. Vale, pues cuando tiene esta información, él opera y produce la suma normal. Un once. Y este número once, cuando lo concateno con un string, sí que produce una operación de concatenación. Pero ojo porque se va a comportar así. No esperéis que esto dijera cinco seis hola. No. Hace una suma, porque primero tiene dos datos que puede sumar. Por tanto estoy llamando al operador suma de números. Y después estoy llamando al operador suma de estilo concatenación. Por eso, si invierto el orden y hago hola cinco seis, lo que sucede es esto otro. ¿Por qué? Pues porque primero suma esto, que produce una cadena y hace una concatenación. Hola cinco. Vale. Y hola cinco, ¿qué es? Una cadena que concatenada con un número produce otra cadena. Por eso tenemos este comportamiento curioso. ¿Vale? Curioso. Es lógico, pero que no se engalle. Vale. Con esta instrucción, System.out.println, yo puedo imprimir. En la práctica, el método más sofisticado que tenemos es uno que se llama imprimir printinfo. Nos piden que hagamos uno que se llame printinfo. Bueno, pues un printinfo sería algo así. Es un método que a base de System.out.println muestra los valores de todos los atributos. En este caso solo tenemos este. Este sería un atributo de un ticket. Pero si estoy intentando hacer un ticket, un printinfo de la clase componente, lo que haría sería hacer una serie de System.out.println mostrando atributo a atributo la información que contiene. Simplemente es eso. O sea, yo creo que extrapolando este ejemplo ya tenéis cómo hacer este printinfo. Ahora bien, fijaos que esto es un método de tipo get. No devuelve nada. No necesita parámetros porque ya tiene toda la información para trabajar y simplemente no es que devuelva nada al sistema, sino que ejecuta comandos que tienen un efecto secundario. Esto no es que devuelva nada. Es que ejecutar un System.out.println hace que por la pantalla de texto se produce una salida. Por eso no necesita un tipo de retorno. Esta forma es la que os sugiere el equipo docente para que hagáis vuestra práctica. Y no hay ningún problema en principio. Pero si queréis una recomendación y hacer una reflexión, es un poco mejor criticar un poco esta forma de hacer. Si yo en el método de un objeto hago System.out.println, ¿qué me va a pasar? Voy a tener al menos dos problemas. Primero, este método va a quedar fijo a piñón con un formato invariable. Es decir, esta decoración de poner estrellitas o rayas o lo que queráis no va a ser modificable. Desde quien llame a esta función imprimirTicket, el ticket siempre les saldrá igual. Pero tiene un problema todavía más grave, que es que es dependiente de la consola. ¿Qué quiere decir la consola? La consola es mostrar mensajes en una pantalla negra escritos en blanco. Hoy en día los programas modernos en Java no enfrentan al usuario a manejar el terminal de texto o la línea de comando, sino que arrojaría a lo mejor una ventanita muy buena con un icono que mostraría el ticket de su compra o lo sacaría por la impresora. De este modo, este método es poco versátil porque sólo está pensado para trabajar con el terminal. Si yo quiero hacer objetos que pueda usar en una aplicación de terminal o bien los pueda usar en otra aplicación más sofisticada, éste está trabado a una forma de mostrar los resultados. Esto es una pequeña crítica. En general, cuando tú haces un diseño orientado a objetos, te interesa que esos objetos los puedas utilizar muchas veces en múltiples proyectos. Si tú te curras en una aplicación un imprimir factura, o más que un imprimir factura, obtener factura de un sistema, te interesará a lo mejor hoy utilizarla para mandarla a la impresora y mañana el obtener factura para mostrar una impresión en PDF. Por ejemplo, generar un PDF. Pues este método nos sirve para eso. Este método, siempre que sea invocado, sacará un mensaje por la consola. ¿Qué podríamos hacer? Cambiar un poco el método y en lugar de hacer System of Println dentro, que el método devuelva un string, si queréis también formateado, y hacer el System of Println en el programa principal. De este modo, lo único que tengo que cambiar es el programa principal, pero los objetos son versátiles. Los podría utilizar tanto en un programa principal que fuera haga System of Println, como en un programa principal que haga otra cosa. Es decir, me gusta un poco más si cambio el planteamiento. Una alternativa sería hacer este método, en lugar de llamarlo imprimirTicket lo llamaré getTicket. ¿Por qué? Pues porque lo que va a hacer es devolver un string. ¿Y qué hace este método? Pues lo mismo que el otro, pero directamente un solo return, que devuelve una concatenación larga de texto y este símbolo, que significa saltos de línea. De esta forma tengo un string que incorpora saltos de línea. ¿Y qué hago en el programa principal? Simplemente System of Println, porque me interesa no complicarme la vida y para hacer la práctica que vamos a hacer, mostrarlo por pantalla, y llamo al objeto, aquí tengo un error, e invoco la función getTicket. Aquí tengo un error porque debería poner paréntesis, paréntesis. Cuando tú llamas al método, si no tiene parámetros, lleva la lista de parámetros también vacía. También lo tengo que corregir. ¿Vale? El formato, sí es verdad, sigue siendo fijo porque este formateo con cuadritos y con saltos de línea no lo voy a poder cambiar, pero al menos es más polivalente en este sentido que os he dicho antes, porque simplemente devuelve un string. ¿Este string qué puedo hacer con él? Pues ya en el programa principal, puedo jugar mucho más con este string. Lo puedo utilizar como para decorar una ventana gráfica, o lo puedo mandar al terminal, o lo puedo mandar a la impresora, o lo puedo utilizar en una función más compleja que genere un PDF con este string. Vale. Una pequeña cuestión, una duda que os quiero plantear. Si os fijáis, un poco por estética, he terminado este string con dos saltos de línea. Si yo llamo esta función sistema.oprntln objeto.getTicket ¿cuántos saltos de línea voy a tener después? Os lo planteo si queréis. Para la práctica mejor utilizar esta alternativa. La verdad es que me gusta más. Si alguien se toma esta molestia de mostrar esta alternativa, es decir, en general la consigna sería no uséis system.oprntln dentro de vuestros métodos, usadlos en el programa principal. Si hacéis este esfuerzo, yo lo consideraré un punto más de calidad. Siempre hay un pequeño margen subjetivo de qué tal es el estilo de programación de este código. Consideraré que habéis hecho un pequeño esfuerzo para hacer vuestro código un poco más flexible. Pero tampoco si alguien utiliza la forma anterior, aprobará y connota si el resto de la práctica está bien resuelta. Es un detalle menor. Pero por ser puntilloso, la programación orientada a objetos pierde en pocos sentidos si haces cosas como estas. En general lo que sucede en una aplicación moderna de orientación a objetos es que tienes objetos que implementan la lógica del negocio y otros objetos especializados en la presentación de un determinado tipo. De manera que los objetos de negocio no muestran nada. Son los especializados en mostrar que tendrás objetos especializados para mostrar de forma gráfica o de un tipo o de otro para mandar la información luego por internet. Pero los objetos de negocio, los que definen la lógica de las facturas de los procedimientos de los clientes son procedimientos digamos más polivalentes. Bueno, más o menos estamos a la mitad de tiempo. Hacemos una pequeña pausa si os parece. Dejadme ver qué viene a continuación para saber si es un momento que tiene sentido cortar aquí. Si, es perfecto el momento para cortar. Entonces 10 minutos son las 6 y 20. A las 6 y media más o menos seguimos con el trabajo. ¿De acuerdo? Venga, hacemos una pequeña pausa.