Al trabajar con clases anidadas en Java, es esencial entender su implementación y funcionalidad. Estas clases permiten estructurar el código de manera eficiente y refinar el control sobre el acceso a los métodos y atributos. Veamos cómo podemos realizar la implementación práctica en un escenario simulado que se asemeja a la lectura de un libro.
¿Cómo crear y manejar un ArrayList de páginas?
Para simular la lectura de un libro, primero es necesario crear un ArrayList que contenga objetos de la clase Page. Estos objetos representan cada página del libro.
privateArrayList<Page> pages;
Para acceder y modificar esta lista de páginas, es conveniente encapsular el atributo y proporcionar métodos getter y setter.
¿Cómo simular la lectura de un libro?
En esta simulación, la lectura se realiza a través de un bucle do-while, que itera sobre las páginas y permite al usuario avanzar o retroceder.
int i =0;do{System.out.println("Número de página: "+getPages().get(i).getNumber());System.out.println(getPages().get(i).getContent());if(i !=0){System.out.println("1. Regresar página");}System.out.println("2. Siguiente página");System.out.println("0. Cerrar libro"); response =AmazonUtil.validateUserResponseMenu(0,2);if(response ==2){ i++;}elseif(response ==1){ i--;}elseif(response ==0){break;}}while(i <getPages().size());
¿Cómo construir la lista de páginas?
Podemos construir una lista de objetos de la clase Page y asignarla al libro mediante el constructor.
ArrayList<Page> pages =newArrayList<>();for(int i =0; i <3; i++){ pages.add(newBook.Page(i +1,"Contenido de la página "+(i +1)));}
El constructor del libro debe modificarse para recibir esta lista de páginas.
¿Cómo verificar y depurar el proyecto en Eclipse?
Si un error del entorno de desarrollo afecta la ejecución:
Utilizar la función de limpieza del proyecto: Project -> Clean.
Reiniciar Eclipse puede resolver problemas sin identificar claramente.
Asegurarse de que el código fuente esté libre de errores lógicos.
¿Qué sigue después de implementar clases anidadas?
El mejor uso de una clase anidada depende del contexto del negocio y de cómo se relacionan las entidades dentro de la aplicación. Una vez que domines esta técnica, puedes aprovechar su potencia para organizar y gestionar de manera eficiente las aplicaciones Java más complejas.
¡Sigue explorando más sorpresas y técnicas avanzadas en las próximas lecciones! El conocimiento siempre tiene un vasto campo de aplicación, y la práctica continua fortalecerá tu habilidad para desarrollar soluciones innovadoras y robustas.
Faltó validar que cuando se esté en la primera pagina del libro y el usuario marque la opción 1, que aunque no se muestre en pantalla la opción, igual la marque no disminuya en uno a i ya que tomará valor de -1 y esto generará una Exception al leer el ArrayList.
int response =AmazonUtil.validateUserResponseMenu(0,2);if(response ==2){ i++;}//faltó poner que esto se haga mientras i sea mayor a 0elseif(response ==1&& i>0){ i--;}elseif(response ==0){break;}
En que parte del proyecto del curso anterior crearon la librería de AmazonUtil, ya que vengo de ver ese curso y no esta esa creación en que parte de la edición quedo cortada gracias… ???
Amigo es verdad, pero entonces lo mejor es antes de comenzar a modificar todo el código copiarlo de como está en los recursos al inicio del curso para que no hayan diferencias con lo que se hace a continuación en el curso.
No le veo ninguna utilidad a las clases anidadas más que para hacer un código horroroso. ¿Acaso para evitar el problema de tener un lío de clases no se tiene la solución de crear los paquetes?
Están más enfocadas en la lógica del negocio, la verdad es que encapsular código es muy buena práctica que cuando tienes un proyecto muy grande agradeces que las clases estén encapsuladas de acuerdo a su lógica en el negocio.
Las clases anidadas nos ofrecen una buena legibilidad de código, ¿como? se preguntaran.
Existen clases que inevitablemente van a trabajar o a estar fuertemente relacionadas con otras clases, si bien podemos crear estas clases en otro lugar e igualmente funcionarían, anidar clases te permite agrupar aquellas que trabajan juntas.
En lo personal creo que un buen programador se da la oportunidad de probar la herramienta antes de criticarla y decidir no usarla.
Buenas comunidad, si buscan la clase de amazonUtil, posiblemente la conseguiran en extension .class, asi que las voy a dejar en extension .java para que la puedan descargar.
Hola! Hago la misma pregunta que hice antes:
Vengo haciendo el Path de Backend con Java, desde el principio. Y no vi en que momento desarrollaron TODO este proyecto. Me gustaria que me puedan indicar en que lugar se hizo y reportar un problema en la construccion del path.
Saludos!
Por que razon al mometo de adicionar el parametro _pages _dentro del metodo costructor Book() no lo asignamos usado el metodo getter como siempre lo haciamos
La logica de negocio depende de cada empresa de como lo apliques. Es decir, los requerimientos del usuario. Por ejemplo: a ciertos clientes se les debe dar descuento y al realizar la compra enviar la factura por correo.
Cosas asi es la logica del negocio.
Acá dejo mi versión del la clase Book, yo preferí manejar un método makePagesForBook() dentro de la clase Page ya que en mi opinión es mejor manejar lo más desacopladas posible las clases. Igual es solo otra forma de hacerlo.
Book
import com.erosennin.amazonviewer.utils.Utils;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;publicclassBookextendsPublicationimplementsVisualizable{private int id;privateString isbn;privateArrayList<Page> pages;privateDate startDate;publicBook(String title,String editorial,String[] authors,Date publicationDate,String isbn, boolean readed,ArrayList<Page> pages){super(title, editorial, authors, publicationDate);super.setReaded(readed);this.isbn= isbn;this.pages= pages;}publicvoidsetId(int id){this.id= id;}public int getId(){return id;}publicStringgetIsbn(){return isbn;}publicstaticList<Book>makeBooksList(){List<Book> books =newArrayList<>();String[] authors =newString[3];for(int i =1; i < authors.length; i++){ authors[i]="Author "+ i;}for(int i =1; i <6; i++){ books.add(newBook("Book "+ i,"Editorial "+ i, authors,newDate(),"ISBN "+ i,false,Page.makePagesForBook()));}return books;}public int getLastPageReaded(){ int lastPageReaded =0;for(int i =0; i < pages.size(); i++){if(pages.get(i).isReaded().equals("No")){ lastPageReaded = pages.get(i).getNumber()-1;if(i !=0){ lastPageReaded--;}break;}elseif(i == pages.size()-1){ lastPageReaded = pages.size()-1;}}return lastPageReaded;}publicvoidview(){startToSee(newDate()); int lastPageReaded =getLastPageReaded();System.out.println(lastPageReaded);do{System.out.println("\n :: "+getTitle()+" :: ");System.out.println("\n...Page "+ pages.get(lastPageReaded).getNumber()+"...");System.out.println(".........");System.out.println(pages.get(lastPageReaded).getContent());System.out.println(".........\n"); pages.get(lastPageReaded).setReaded(true);if(lastPageReaded !=0){System.out.println("1. Previous Page");}System.out.println("2. Next Page");System.out.println("0. Close Book");String option =Utils.validateUserResponseMenu(2);switch(option){case"2": lastPageReaded++;break;case"1":if(lastPageReaded !=0){ lastPageReaded--;}else{System.out.println("\nThat option doesn't exist, please choose another.\n");}break;case"0": lastPageReaded = pages.size();break;}}while(lastPageReaded < pages.size());stopToSee(newDate());System.out.println("\n::YOU JUST SAW::\n"+toString());setReaded(true);} @OverridepublicStringtoString(){StringBuilder printerAuthors =newStringBuilder();String[] authors =getAuthors();for(Stringauthor: authors){ printerAuthors.append(author).append(", ");} printerAuthors.delete(printerAuthors.length()-2, printerAuthors.length()-1);return"\n::BOOK::"+"\nTitle: "+getTitle()+"\nPublisher: "+getEditorial()+"\nAuthors: "+ printerAuthors +"\nPublication Date: "+newSimpleDateFormat("dd/MM/yyyy").format(getPublicationDate())+"\nISBN: "+getIsbn()+"\nReaded: "+isReaded()+"\nPages: "+ pages.size();} @OverridepublicvoidstartToSee(Date startDate){this.startDate= startDate;} @OverridepublicvoidstopToSee(Date endDate){if(startDate.getTime()< endDate.getTime()){setTimeReaded((int)(endDate.getTime()- startDate.getTime()));}else{setTimeReaded(0);}} @OverridepublicvoidsetReaded(boolean readed){super.setReaded(readed);for(Page page : pages){if(page.isReaded().equals("No")){super.setReaded(false);break;}}}publicstaticclassPage{private int id;private int number;privateString content;private boolean readed;publicPage(int number,String content){this.number= number;this.content= content;}public int getId(){return id;}publicvoidsetId(int id){this.id= id;}public int getNumber(){return number;}publicStringgetContent(){return content;}publicStringisReaded(){return(readed)?"Yes":"No";}publicvoidsetReaded(boolean readed){this.readed= readed;}publicstaticArrayList<Page>makePagesForBook(){ArrayList<Page> pages =newArrayList<>();for(int i =1; i <7; i++){ pages.add(newPage(i,"Content...\nContent...\nContent...\nContent..."));}return pages;}}}
Y acá dejo mi clase Utils para referencia:
Utils
package com.erosennin.amazonviewer.utils;import java.util.Scanner;import java.util.concurrent.TimeUnit;publicclassUtils{publicstatic boolean isNotNumber(String string){ boolean res =false;if(string.length()==0){ res =true;}for(int i =0; i < string.length(); i++){if(!Character.isDigit(string.charAt(i))){ res =true;break;}}return res;}publicstaticStringvalidateUserResponseMenu(int size){Scanner scanner =newScanner(System.in);String option = scanner.next();if(Utils.isNotNumber(option)){System.out.println("\nThat option doesn't exist, please choose another.\n"); option ="";}elseif(Integer.parseInt(option)<0|| size <Integer.parseInt(option)){System.out.println("\nThat option doesn't exist, please choose another.\n"); option ="";}return option;}publicstaticvoidtimeDelay(int seconds){try{TimeUnit.SECONDS.sleep(seconds);}catch(InterruptedException e){ e.printStackTrace();}}}
Y acá dejo mi proyecto completo en GitHub para los que los quieran revisar:
La única observación que podría decir en cuanto a la lógica, es que si yo sólo 2 páginas (de las 3 que tiene un libro) ya me dice que lo leí lo cuál no debería ser así. O si el libro lee la primera página, luego la segunda, y me devuelvo a la primera, no quiere decir que ya me leí todo el libro. Debe marcar que el libro fue leído cuando TODAS las páginas fueron leídas, así como lo hacemos con los capítulos de una serie.
El código sería el siguiente:
Book.java
publicvoidview(){Date dateI =this.startToSee(newDate()); int numberPagesRead =0;do{System.out.print("........\n");System.out.println("Page: "+this.getPages().get(numberPagesRead).getNumber());System.out.println("Content: "+this.getPages().get(numberPagesRead).getContent());AmazonUtil.seenThread();this.getPages().get(numberPagesRead).setRead(true);System.out.print(".......\n");if(numberPagesRead !=0)System.out.println("1. Regresar Página");System.out.println("2. Siguiente Página");System.out.println("3. Cerrar Libro\n"); int opcion =AmazonUtil.validateUserResponseOptionMenu(1,3,"Elige una opción: ");if(opcion ==2) numberPagesRead++;elseif(opcion ==1) numberPagesRead--;elseif(opcion ==3)break;}while(numberPagesRead <getPages().size()); int pagesReadBook =0;for(Page p : pages){if(p.isRead()){ pagesReadBook++;}}if(pagesReadBook ==getPages().size())this.setRead(true);this.stopToSee(dateI,newDate());System.out.println("Viste \""+this.getTitle()+"\" en "+this.getTimeRead()+" segundos !! ");}publicstaticclassPage{private int id;private int number;privateString content;private boolean read;publicPage(int number,String content){super();this.number= number;this.content= content;}public int getId(){return id;}publicvoidsetId(int id){this.id= id;}public int getNumber(){return number;}publicvoidsetNumber(int number){this.number= number;}publicStringgetContent(){return content;}publicvoidsetContent(String content){this.content= content;}public boolean isRead(){return read;}publicvoidsetRead(boolean read){this.read= read;}}
Aquí esta el código de AmazonUtil.java
<package com.anncode.util;import java.util.Scanner;publicclassAmazonUtil{publicstatic int validateUserResponseMenu(int min, int max){//Leer la respuesta del usuarioScanner sc =newScanner(System.in);//Validar respuesta intwhile(!sc.hasNextInt()){ sc.next();System.out.println("No ingresaste una opción válida1");System.out.println("Intenta otra vez1");} int response = sc.nextInt();//Validar rango de respuestawhile(response < min || response > max){//Solicitar de nuevo la respuestaSystem.out.println("No ingresaste una opción válida");System.out.println("Intenta otra vez");while(!sc.hasNextInt()){ sc.next();System.out.println("No ingresaste una opción válida");System.out.println("Intenta otra vez");} response = sc.nextInt();}System.out.println("Tu Respuesta fue: "+ response +"\n");return response;}}>