Created
June 24, 2022 21:52
-
-
Save flbulgarelli/3a09fb7450b54ecb696bb74324239cc4 to your computer and use it in GitHub Desktop.
QMP5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ## Antes de empezar | |
// El código y el diagrama | |
class Prenda { | |
} | |
class Guardarropa { | |
private String nombre; | |
private List<Prenda> prendas; | |
} | |
class Usuario { | |
private Guardarropa guardarropa; | |
} | |
// ## Punto 1: Guardarropa múltiples | |
// | |
// Como usuarie de QuéMePongo, quiero poder manejar varios guardarropa para separar mis prendas según diversos criterios (ropa de viaje, ropa de entrecasa, etc). | |
class Usuario { | |
private List<Guardarropa> guardarropas; | |
} | |
dani.crearGuardarropa("deportivo") | |
dani.agregarGuardarropa(new Guardarropa("deportivo")) | |
// * Los criterios no son parte del software | |
// * Es un requerimiento trivial | |
// ## Punto 2: Guardarropas compartidos | |
// Como usuarie de QuéMePongo, quiero poder crear guardarropas compartidos con otros usuaries (ej, ropa que comparto con mi hermane). | |
// Opción 1: para tener guardarropas compartidos, | |
// simplemente compartimos al guardarropas | |
Guardarropa guardarropa = feli.crearGuardarropa() | |
guardarropa.compartirCon(dani) | |
// o incluso... | |
dani.agregarGuardarropa(guarropa) | |
class Guardarropa { | |
void compatirCon(usuarie) { | |
usuarie.agregarGuardarropa(this); | |
} | |
} | |
// Opción 2: Agregar a todos los guardarropas una lista de usuaries | |
Guardarropa guardarropa = feli.crearGuardarropa() | |
guardarropa.compartirCon(dani) | |
class Usuario { | |
void crearGuardarropa() { | |
guardarropa = new Guardarropa() | |
guardarropa.compartirCon(this) | |
guardarropas.add(guardarropa) | |
return guardarropa | |
} | |
} | |
class Guardarropa { | |
// ¿Pero no hace falta une admin? | |
List<Usuario> colaboradores; | |
void compatirCon(usuarie) { | |
colaboradores.add(usuarie); | |
usuarie.agregarGuardarropa(this); | |
} | |
} | |
// y probablemente haya más grises que no estoy contemplando en esta solución.... | |
// Opción 3: Subclasificar | |
feli.crearGuardarropaCompartidoCon(dani) | |
// o incluso... | |
feli.agregarGuardarropa(new GuardarropaCompartido([dani])) | |
// ## Punto 3 y 4: Las propuestas de agregar y quitar | |
// Como usuarie de QuéMePongo, quiero que otro usuario me proponga tentativamente agregar una prenda al guardarropas. | |
// Como usuarie de QuéMePongo, quiero que otro usuario me proponga tentativamente quitar una prenda del guardarropas. | |
// * ¿Dónde va? ¿Usuario o guardarropas? ¿A quien afecta? ¿Hubiera sido lo mismo si hubieramos tenido sólo un guardarropas? | |
// * Se puede hacer bien más sencillo | |
guardarropa.agregarPropuestaDeAgregado(saco) | |
guardarropa.agregarPropuestaDeQuitado(saco) | |
// o incluso... | |
guardarropa.proponerAgregar(saco) | |
guardarropa.proponerRemover(saco) | |
// quizás podría ser algo así... (sólo la implementación nos dirá luego si tiene sentido) | |
saco.ofrecerAgregarA(guardarropa) | |
saco.ofrecerQuitarA(guardarropa) | |
class Guardarropa { | |
List<Prenda> prendas; | |
// y demás atributos con los que ya contábamos... | |
List<Prenda> propuestasDeAgregado; | |
void proponerAgregar(Prenda prenda) { | |
propuestasDeAgregado.add(prenda) | |
} | |
} | |
// pero cuando hay que extender se vuelve repetitivo y disminuye su mantenibilidad... | |
guardarropa.proponerRemover(saco) | |
class Guardarropa { | |
List<Prenda> propuestasDeAgregado; | |
List<Prenda> propuestasDeRemocion; | |
void proponerAgregar(Prenda prenda) { | |
propuestasDeAgregado.add(prenda) | |
} | |
void proponerRemover(Prenda prenda) { | |
propuestasDeRemocion.remove(prenda) | |
} | |
} | |
// pero aún así, funciona, ¿no? | |
Prenda saco = new Prenda(...) | |
juli.proponerAgregar(dani, saco) | |
class Usuarie { | |
void proponerAgregar(destinatarie, prenda) { | |
destinatarie.proponerAgregar(prenda) | |
} | |
} | |
// no vamos a ir por acá, porque esto termina siendo un missplaced method | |
// que parte de la confusión entre actor y objeto | |
// Punto 5: listar, aceptar y rechazar | |
// Como usuarie de QuéMePongo, necesito ver todas las propuestas de modificación (agregar o quitar prendas) del guardarropas y poder aceptarlas o rechazarlas. | |
// * Listar no necesita mucho más | |
// * Pero ahora sí hay comportamiento (y polimórfico) | |
class Guardarropa { | |
List<Propuesta> propuestas; | |
// BEGIN OPCIONAL | |
Propuesta proponerAgregar(Prenda prenda) { | |
Propuesta propuesta = new PropuestaAgregar(prenda); | |
this.proponer(propuesta) | |
return propuesta | |
} | |
Propuesta proponerRemover(Prenda prenda) { | |
Propuesta propuesta = new PropuestaRemover(prenda) | |
this.proponer(propuesta) | |
return propuesta | |
} | |
// END OPCIONAL | |
void proponer(Propuesta propuesta) { | |
propuestas.add(propuesta) | |
} | |
} | |
guardarropa.proponerAgregar(saco) | |
guardarropa.proponerRemover(saco) | |
interface Propuesta { | |
void aceptar(Guardarropa guardarropa) | |
void rechazar(Guardarropa guardarropa) | |
} | |
class PropuestaAgregar implements Propuesta { | |
private Prenda prenda; | |
constructor(prenda) { ... } | |
void aceptar(guardarropa) { | |
guardarropas.agregarPrenda(prenda) | |
} | |
} | |
class PropuestaRemover implements Propuesta { | |
private Prenda prenda; | |
constructor(prenda) { ... } | |
void aceptar(guardarropa) { | |
guardarropas.quitarPrenda(prenda) | |
} | |
} | |
// opción 1 | |
// t_0 | |
propuesta = guardarropa.proponerAgregar(saco) | |
// t_1 | |
propuesta.aceptar(guardarropa) | |
// nota: si el guardarropa hubiera sido estado de la propuesta, se podría haber omitido el argumento guardarropa, así: | |
// propuesta.aceptar() | |
// opción 2 | |
// a favor: nos hace más fácil validar y/ o remover las propuestas | |
// en contra: no nos permite hacer nada que no pudieramos hacer de la otra forma | |
// | |
// De todas formas, aunque podría ser, en principio no hay en este ejercicio un buen motivo para hacer validaciones | |
// t_0 | |
propuesta = guardarropa.proponerAgregar(saco) | |
// t_1 | |
guardarropa.aceptarPropuesta(propuesta) | |
class Guardarropa { | |
void aceptarPropuesta(propuesta) { | |
propuesta.aceptar(this) | |
propuestas.remove(propuesta) | |
} | |
void rechazarPropuesta(propuesta) { | |
propuesta.rechazar(this) | |
propuestas.remove(propuesta) | |
} | |
// NOTA MENTAL: esta idea de remover también sería necesaria en la variante anterior | |
// ¿es necesario? | |
// ¿el flujo no podría garantizar que siempre se reciban propuestas pendientes? | |
// No estamos diciendo que SIEMPRE será innecesario, | |
// pero ojo que no es un requerimiento explícito en este punto | |
boolean estaPendiente(propuesta) { | |
return propuestas.contains(propuesta) | |
} | |
} | |
// variantes erróneas: | |
class Guardarropa { | |
void aceptarPropuesta(propuesta) { | |
propuesta = propuestas.find { it => it == propuesta } // MAL MAL MAL A NIVEL OBJETOS | |
propuesta.aceptar(this) | |
propuestas.remove(propuesta) | |
} | |
} | |
class Guardarropa { | |
void aceptarPropuesta(propuestaId) { | |
propuesta = propuestas.find { it => it.id == propuestaId } // MAL MAL MAL porque estamos mezclando ideas de persistencia que podŕiamos resolver de formas más sencillas y automáticas | |
propuesta.aceptar(this) | |
propuestas.remove(propuesta) | |
} | |
} | |
// * Marcar vs sacar de colecciones | |
// * ¿Es necesario mantener despues de ejecutar? | |
// * hacer o no hacer, esa es la pregunta | |
// * Acá podría surgir una abstracta | |
class PropuestaDeAgregado implements Propuesta { | |
... | |
void rechazar(...) { | |
// hacer o no hacer, esa es la cuestión | |
} | |
} | |
// * Nota lateral: IInterfaz -.- | |
// * ¿Dobles relaciones? | |
// Punto 5: arrepintiéndonos | |
// Como usuarie de QuéMePongo, quiero poder deshacer las propuestas de modificación que haya aceptado. | |
// A nivel implementación el deshacer | |
// se trata de simplemente jugar con el add y remove de la lista | |
// de propuestas y tener un mensaje adicional que hace lo contrario al | |
// aceptar | |
// * Es otra justificación para esta estructura, pero no es necesario | |
// * ¿Funcionará? Depende del orden | |
// * Nota final sobre el asincronismo |
Author
flbulgarelli
commented
Jun 24, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment