Open maguimarijuan opened 6 years ago
¡Buen día!
Pensando en la re-implementación del patrón de estados de reparacion para los edificios se me presentó un problema.
Lo que quiero lograr es que como hablamos el comportamiento de reparar() esté contenido dentro de cada estado (daniado, yaReparado, vidaCompleta, etc) pero si lo que reparar debe hacer es cambiar el valor del atributo vida del edificio, ¿cómo podemos implementar eso?
Ordeno un poquito la pregunta, ¿Cómo podríamos desde estadoReparacion modificar un atributo (vida) que es de la clase Edificios?
Saludos, Lorenzo
Buenas! mmm qué buena pregunta! ja! ¿Tendría sentido que la vida sea un atributo del estado? Capaz por acá hay una posible solución. Que cada estado pueda responder a la cantidad de vida. Creo que hay un estado que es vida completa una vez que sale de este estado pasa a otro que es estado a reparar y administra la vida de manera distinta. No se si es una buena solución (no hay soluciones buenas) pero capaz va por ahí. De otra manera, podemos seguir charlandolo.
Saludos!
¡Capaz que si! Mañana voy a intentar implementarlo, gracias por la pronta respuesta
Saludos!
Hola Magui!
Recién pushee una refactorización de los estados en algo más orientado a lo que habíamos hablado (que reparar() sea un metodo propio del estado) pero aún hay una pequeña parte de la implementación que si o si debe estar "expuesta" en edificio, que es cuando yo tengo que hacer transicionar un estado a otro (por ejemplo de daniado a vidaCompleta o de daniado a YaReparado) y eso está en el método actualizarEstado() propio de edificio que se llama luego de reparar()
No se me ocurrió algo mas "limpio", despues si le podes echar un ojo te lo re agradecería
Saludos y buen finde!
Hola Magui!
Seria algo logico mostrarle al usuario (ya sea mediante un menu o lo que sea) ataques que solo son posibles con la unidad con la que esta? Re armando un poco, solo mostrarle los ataques q puede hacer si quiere atacar y no dejar que envie un ataque a una posicion no valida ( ya sea porque esta vacia o porque esta fuera de su rango )?
Hola Magui!
Recién pushee una refactorización de los estados en algo más orientado a lo que habíamos hablado (que reparar() sea un metodo propio del estado) pero aún hay una pequeña parte de la implementación que si o si debe estar "expuesta" en edificio, que es cuando yo tengo que hacer transicionar un estado a otro (por ejemplo de daniado a vidaCompleta o de daniado a YaReparado) y eso está en el método actualizarEstado() propio de edificio que se llama luego de reparar()
No se me ocurrió algo mas "limpio", despues si le podes echar un ojo te lo re agradecería
Saludos y buen finde!
Ahora veo esto y les doy una mano!
Hola Magui!
Seria algo logico mostrarle al usuario (ya sea mediante un menu o lo que sea) ataques que solo son posibles con la unidad con la que esta? Re armando un poco, solo mostrarle los ataques q puede hacer si quiere atacar y no dejar que envie un ataque a una posicion no valida ( ya sea porque esta vacia o porque esta fuera de su rango )?
Mmmm! Creo que tenes dos opciones: -Mostrale todos los ataque posibles y avisarle con un cartel cuando haga click en alguno no posible. -Mostrale sólo los que puede hacer.
Si entiendo bien tu pregunta las dos opciones están bien siempre que no se de el caso que se produzca algún movimiento inválido.
Saludos! perdón la tardanza.
Hola magui, te dejo un diagrama tentativo del modelo que estamos pensando, te lo resumo un poco
hay 1 clase jugador que contiene
Cada Jugador tiene:
Cada Elemento tiene
Asi tambien el casillero tiene una referencia al elemento al que contiene pudiendo acceder a el mediante un casillero, o acceder a un casillero mediante un elemento
El mapa no hace distincion entre jugadores solo tiene una lista de casilleros.
Hola! Estuve viendo su TP y tengo un par de observaciones: (les dije que no trabajaran en distintos branches, me costó ver todo asique si falta algo avisenme) 1) En cuanto a los commits personals creo que los tres están trabajando parejo. 2) En cuanto a las pruebas, faltan un par y algunas tienen dos asserts, asegurense de que sean incrementales y unitarias. 3) Yo se que les había dicho que tengan un "actualizar estado" pero ahora que lo veo es horrible jaja, Creo que reparar debería devolver una instancia del estado. 4) No hay cambios en coordenadas. Veo que trataron de implementar lo de la lista en mapa pero aún así no lo hicieron del todo. 5) Busquen algún patron "creacional" para el mapa como un factory quizas. 6) El método de actualizar jugador (en la clase partida) se les ocurre alguna menara de quitar ese if (por qué no se conocen los jugadores y ellos devuelve quién sigue, imaginen que en vez de Age of Empires fuera algún juego de cartas e implementaran así como hicieron la ronda, sería un horror) 7) Construir edificio sigue recibiendo las coordenadas. Se rompe el encapsulamiento. 8) ¿Quién settea el estado de aldeano? Aquel que lo haga sabe que aldeano tiene estados y se rompe el encapsulamiento. No sería mejor que le diga aldeano "construí" y aldeano modifique o no su estado. 9) Sean creativos y busquen otro patrón para el TP -> suma muchisimos puntos. 10) Para el jueves hagan diagramas de secuencias y de clases que vamos a ver muchisimo el modelo para que puedan hacer la interfaz. Si arreglan las cosas que mencioné antes empiecen con la interfaz.
Saludos!
Seguro que a la noche lo vuelvo a ver para ver más correcciones porque siempre hago dos o tres vistas al código.
Hola, Magui
¡Gracias por todo el feedback! Me gustaría replicar un par de detalles que estuvimos arreglando sobre las observaciones.
El tema de los branches fue porque dado que estábamos bastante enredados en el modelo decidimos empezar "limpios" en una branch nueva (nuevoModelo) , para evitar problemas en el build y en las pruebas cada vez que refactorizabamos, ahora que casi lo estamos cerrando lo pasamos al master y lo dejamos ahi!
Las pruebas con doble assert, si, ¡se nos re pasó! fue parte de querer importar las pruebas "viejas", ahora en el refactor deberían volar
Respecto de la coordenada, tuvimos un debate sobre si prescindir de ella o no, en principio, decidimos usar Casillero para tener el "mapa" como un array, pero aún así, dado que siempre ibamos a contar con un par ordenado (x,y) a la hora de referirnos a un lugar específico (como por ejemplo calcular una distancia) , le vimos poco sentido a "sacar" coordenada solo para crear una clase "simplificada" de ella que haga casi lo mismo.
Los aldeanos son creados en el constructor con estadoInactivo y son actualizados de manera automática conforme se les pide hacer algo, creemos utilizar el setter cuando haya que pasar el turno para devolverlos al estado "original" (el que les permitiria hacer cosas en ese nuevo turno)
Lo de sumar otro patrón es algo que tenemos re pendiente!!! Creo que fue encariñarnos con el de Estado, pero planeamos sumar más conforme podamos.
Sobre todas las otras observaciones estamos trabajando
De nuevo muchas gracias por tomarte el tiempo
Saludos!
Yo se que les había dicho que tengan un "actualizar estado" pero ahora que lo veo es horrible jaja, Creo que reparar debería devolver una instancia del estado.
¡Con esta me partiste al medio! En nuestra implementación cuando a un aldeano que no puede reparar se le pide unAldeano.reparar() , lanza AldeanoOcupadoError y si eso sucede (no estoy seguro, lo googlé nada mas jaja) no seguiría ejecutando el método y el return no se haría, por ende no se como sería.
Trato de ejemplificarlo mas facil:
Tenemos esto
//////En aldeano///////
public void reparar(unEdificio){
this.estadoReparacion.reparar(unEdificio);
this.estadoReparacion = this.estadoReparacion.actualizarEstado();
}
Si quisieramos algo así
//////En aldeano///////
public void reparar(unEdificio){
this.estadoReparacion = this.estadoReparacion.reparar(unEdificio); /// <-- acá que pasa?
}
donde la excepción se llamaría en:
//////En un estado donde NO se puede reparar (por ejemplo constructor)///////
public EstadoReparacion reparar(unEdificio){
public EstadoReparacion reparar(unEdificio){
throw new AldeanoOcupadoError(); ////<---- acá se lanza
return new EstadoConstructor();
}
}
Si desde el reparar de estado se lanza una excepción, ¿va a devolver ese nuevo estado estado? ¿o va a devolver null?
Ültima! (perdon por mandar todo junto es que después hasta la noche no vuelvo a codear)
De momento el Unidad.mover(unCasillero) solo verifica que el casillero este vacío, y que esté a una distancia menor a uno, pero el comportamiento que falta agregar es que solo se puedan mover una vez por turno, y quiero inclinarme por algún patron de diseño pero no se cual, y además tengo un pequeño dilema.
El mover está asi:
////En Unidad.java
public void mover(Casillero nuevoCasillero)throws CasilleroAlejadoError, LugarOcupadoError {
if(this.posicion.distanciaHasta(nuevoCasillero) > 1)
throw new CasilleroAlejadoError();
if(nuevoCasillero.estaOcupado())
throw new LugarOcupadoError();
this.posicion.remover();
nuevoCasillero.colocar(this); ///// Esto es lo que no se me ocurre hacer desde un estado
this.posicion = nuevoCasillero; //// Esto si se puede, si hacemos "posicion" un atributo de estado
}
Dado que al mover yo tengo que decirle al nuevoCasillero "bueno, ahora yo <
Un re lío de palabras, yo había pensado algo así:
Unidad -(tenga)--> EstadoMovimiento --(tenga)--> PosicionActual y metodo mover(Casillero)
Pero como hago si le paso el comportamiento a un EstadoMovimiento para que guarde en casillero una referencia de la Unidad
Respecto al State! Tenés razón, el método set state o actualizar tiene que estar (https://www.youtube.com/watch?v=MGEx35FjBuo) ahí hay un video de como implementarlo correctamente. Tenía razón la primera vez que lo vi y no se porque la segunda dudé. Te pido disculpas. Eso es para el primer issue. Esa cuenta de youtube esta mucho muy buena asique si pueden mirenla.
Sobre la segunda preguntas, si un state sería una solución buena pero respondiendo la siguiente pregunta: "Pero como hago si le paso el comportamiento a un EstadoMovimiento para que guarde en casillero una referencia de la Unidad" se me ocurre que estadoMovimiento le diga a casillero: "puedo entrar" y se mande como paramétro (usando self). Me estaría costando una solución, lo estuve pensado y no se me ocurre otra cosa.
Perdonen, voy a consultar otra idea con mis compañeros.
Saludos!
Claro, pero ahora que lo pienso, state le tendría que decir a unidad que le diga a casillero que lo guarde... qué complicado!
Sigo pensandolo jaja!
Como el jueves no va a haber clases, la entrega será online por lo tanto les pido que el jueves (a más tardar el viernes porque tardé en responder y todavía me queda rondando en la cabeza la pregunta anterior) suban una carpeta a git con un par de diagramas de secuencia de estas situaciones y un par de diagramas de clase. Les sugiero que (para ya ir armando el informe) a cada diagrama le agreguen un pequeño texto de qué es lo que resuelven y qué problemas enfrentaron.
También es importante que ya tengan terminado el modelo para empezar con la interfaz gráfica (hagan lo que más puedan).
Saludos!
Hola Magui, viendo cómo estamos la verdad si nos permitís extendernos hasta el viernes para esta entrega vamos a poder llegar con algo bastante más armado. Voy a corregir el tema estado y respecto del mover() que quedó pendiente...
Se me ocurrió (aún no pude implementarlo) que el estadoMovimiento.mover() devuelva el casillero al que la unidad puede moverse de manera que:
-En un estado donde pueda moverse, devuelve el que le corresponde
-En uno dónde no, devuelve en el que la unidad ya estaba.
Se me hace un poco rudimentario pero estuve pensandolo y no se me ocurre una solución más linda
Oki! Hagan una opción que funcione y después lo optimizamos. Terminen el modelo!!! La entrega la paso para el viernes a la noche.
Saludos!
Hola! ¿Cómo están? Estuve viendo su tp! va muy bien! avisenme si tiene alguna duda! Esta noche subo más comentarios.
Estuve con los chicos y no pudimos correr las pruebas, no sé si es un problema mío o si ustedes usaron JUnit 5 y JUnit 4 o algo así raro. Por lo tanto, les pido que me manden qué versión usaron.
Estuve viendo todo lo que está en el branch nuevo modelo. Por lo tanto, si quieren usar distintos branchs haganlo por funcionalidad, pero les recomiendo que usen 1 sola y que unan todo!!!!
Vi los primeros pasos de la interfaz gráfica. Muy buena la presentación!!!
La entrega 3 está aprobada!
Saludos!
PD: Si alguno quiere saber la nota del recuperatorio me puede mandar una mail y les averiguo.
Hola Magui, ¡gracias! - Si, nos estamos manejando con nuevoModelo para el desarrollo y cada tanto hacemos un PR a Master.
Respecto de JUnit, si no estoy equivocado usamos JUnit 4.11 pero ahora que lo mencionas capaz que hay alguna prueba que justo necesitabamos un assert medio rancio e incluímos un paquete que no iba (ej: AssertNotSame)
Aprovecho para hacerte una pregunta del tema Interfaz, más que de interfaz, de MVC, ¿es necesario que tambien utilizemos patrones de diseño y seamos "polimorficos" para esta parte del trabajo? Por ejemplo, a la hora de dibujar un casillero de un color o de otro (según la unidad que tenga) lo que esta hecho es para un casillero que tiene una entidad Posicionable (interfaz de Unidades y Edificios)
if entidad instanceOf(Aldeano) -----> dibuja el colorcito del aldeano y ponele una A al botón
if entidad instanceOf(Castillo) -----> dibuja el colorcito del castillo y ponele una C al botón
Entiendo que en el modelo algo así estaba re mal, pero ¿en la vista si podemos tomarnos estas libertades?
Muchas Gracias!!
Saludos!
El la vista pueden tomarse esas libertades pero no abusen! JAJA! Es mejor usar instanceOf antes que el modelo tenga información de la vista.
Saludos!
jajajaja ay ¡menos mal! Buenísimo, lo hacemos con cautela
Gracias Magui! Saludos
Buenas noches Magui, quería contarte que estuvimos pensando con los chicos que hacer con la entrega del TP y llegamos a la conclusión de que si bien probablemente sigamos trabajando en él (porque tenemos ganas de terminarlo) estamos en una semana (y etapa del cuatri) bastante complicada (por ejemplo Gabi y Martin rinden el recu y yo tengo un final el martes) y no queremos comprometernos a un tiempo que no tenemos para dedicarle, de manera que seguro en unos días puedas chusmear algún que otro cambio (o hasta jugarlo si estas aburrida una tarde jaja) pero fuera de lo que compete a la materia y a esta cursada.
Además, sentimos que la nota final es representativa del esfuerzo puesto y no tenemos más que agradecimientos por toda la ayuda que nos diste a lo largo del desarrollo.
Saludos!
PD: Si todavía siguen en pie esos "tips" para el final, nos vienen muuuuy bien
Oki! Entonces cerramos en 7.5.
Tips para el final: -Leer la unidad de principios solid del libro de Fontela. -Saberse los principios solid DE ME MO RIA. Poder identificarlos. -Leer las lecturas obligatorias aunque sea una vez. -Tener un par de patrones de diseño bajo la manga. -Tener algún patrón creaciones bajo la manga, como aquel que menciona el libro de Fontela para crear un iterador asociado a una lista. -Practicar algún final antes.
Saludos! Mucha suerte!
Magui!
PD: Anótense al final, si pueden lleven la compu.
PD2: Todo lo que creen en el final acompáñenlos con sus pruebas unitarias. No olvidarse bajo ningún punto de TDD y de las buenas prácticas (atributos privados, métodos públicos, clases abstractas, pocos if y encapsulamiento aunque éste último es un solid).
PD3: No olviden que la Herencia es sólo para aquellos casos donde se reutiliza código y el objeto es el que hereda (sustitución de Liskov!!!!!)
PD 4: hagan bien los diagramas (con la notación UML), no se olviden del diagrama de estados, ejem ejem.
Muchas gracias Magui!!! Los vamos a aplicar
Mil gracias magui!!
La nota les cerró con 8! Saludos!
Hola magui, primero gracias por la nota!, te queria preguntar si tenes alguna recomendacion a la hora de encarar un modelo para el recu mañana, Hice parciales pero nunca termino de estar 100% seguro de si lo que hice esta bien o no.. Gracias, saludos
Mmmm, lo que les puedo sugerir es: -que se aseguren de que su modelo funcione. -que el comportamiento que tengan duda lo agreguen como supuesto. -hagan pruebas unitarias si les piden hacer pruebas.
Algunos chicos se equivocan porque hacen una explosión de clases. Fijense que todas sus clases tengan comportamiento y que no haya mucho acoplamiento.
Y como siempre, traten que su diagrama de secuencia se note la delegación! esto es lo más importante!!
Joya, para el ejercicio de la sube, te parece bien que la tarjeta tenga sus viajes y un estado que calcule el descuento correspondiente?
ejemplo:
int cobrarViaje(int costo, Date fecha)
y que calcule ahi el descuenta
o
int costoConDescuento = tarjeta.calcularDescuentoViaje(int costoBase);
tarjeta.cobrarViaje(int costoConDescuento, Date fecha);
el método calcular descuento viaje es un método privado? O alguien sabe que existe ese método? No se rompe un poco el encapsulamiento?
¿Qué opinas de un objeto interno que sepa el estado de los viajes, que se actualice con la fecha? #patronStateForEver. Después la tarjeta delega a este estado el cálculo del viaje.
eso hice el recu pasado, una clase sistema que llevaba registro de los viajes y calculaba el descuento pero nose estaria bien?
Estaría bien siempre y cuando le pases la fecha, tendría que ver el modelo completo!
mi supuesto era q la clase siempre sabia la fecha en la q estaba (tipo relos interno ? ), entonce llevaba un registro de viajes por tarjeta
mmm, me parece un supuesto muy fuerte!
voy a arrancarlo de 0 de nuevo a ver que onda, por eso, no sabia donde meter los viajes si en tarjeta o en alguna otra clase aparte
dale! cuando termines mándame una foto y lo vemos
Aca hice le diagrama de secuencias, una vez terminado pense q la parte de verificar si pude viajar podria evitarla y tan solo esperar una excepcion al cobrar ( de todos modo el enunciado dice que se verifica al inicio si hay saldo suficiente por eso lo deje)
Abro este issue para que me consulten sus dudas de la primera entrega! Abriremos distintos issues para los problemas que tengan. Saludos!