Hola. tengo una duda en un caso puntual, que al irse desarrollando el codigo, van cambiando algunas cosas.
Invento un ejemplo.
En una empresa hay varios jefes, y a los jefes se les asignan días de la semana en la cual los empleados que tienen a cargo pueden usar el telefono.
De tal manera por ejemplo, el empleado de Pedro no puede llamar por telefono los lunes pero si los martes.
Tenemos un empleado y un jefe. el empleado tenia una referencia al jefe.
El empleado tiene que llamar por telefono pero solo lo puede hacer si es su turno de llamar por telefono.
y eso solo lo sabe el jefe.
originalmente cuando se programo. teníamos esta prueba.
empleado.llamarA (pablo)
internamente en empledo hacia
------ if (this.miJefe.esmiTurno) si era true, llamaba.
De esa manera evitábamos que el empleado llamara a Pablo cuando no era su turno.
Ahora cambiamos la implementacion. y las ordenes las da el jefe. (no llama por su cuenta el empleado como antes)
De tal manera que ahora tenemos
jefe.indicarQueLlame(empleado, Pablo) {
empleado.llamarA(Pablo)
}
Con lo cual, el empleado es manejado a través del jefe. y no necesitamos que internamente conozca a su jefe ni chequee si es su turno, por que la orden se la esta dando el jefe (por lo tanto es su turno) (en todo caso el chequeo de turno es del jefe.)
en nuestro esquema, ahora, como el empleado es manejado por el jefe, nunca se podria dar un caso en el que el jefe le diga que llame cuando no es su turno.
La duda es:
En las pruebas de empleado, cambio la prueba vieja que mostraba que no podia llamar si no era su turno, por una que muestre que el empleado puede llamar en cualquier momento.
y en las pruebas de jefe, tendria una prueba que prueba, que el jefe no puede dar una orden de llamar si no es su turno.
Gracias Saludos.
Hola José:
La respuesta corta es que sí a ambas preguntas.
Me parece muy bien el cambio que proponés. La versión original violaba la ley de Demeter y tenía un modelado con un acoplamiento muy alto, pero era válido en una primera iteración de TDD. El problema es que el cambio que hiciste no es una refactorización, dado que tus pruebas originales ya no son válidas. En ese caso cambiaste el modelo por uno distinto en el que la clase Jefe es como una especie de fachada para la clase Empleado, lo cual es válido pero resetea todo el proceso de TDD haciendo que haya que reescribir las pruebas. Por lo que sí, en tu nuevo modelo un empleado solo puede llamar en cualquier momento y debe haber pruebas unitarias para ello y luego las nuevas pruebas unitarias del jefe verifican el tema de los días.
Otra alternativa que no necesariamente es mejor pero que quizás no hubiera requerido tantos cambios en las pruebas sería haciendo que cada empleado tenga una referencia a su respectivo jefe y que le delegara a él la responsabilidad a la hora de realizar la llamada, pasándose a sí mismo como parámetro además del otro empleado:
public void llamarA(Empleado otroEmpleado) { this.jefe.realizarLlamada(this, otroEmpleado); }
En caso de no poder realizar la llamada se podría lanzar una excepción que sería la que se atraparía en las pruebas unitarias. De esta manera el jefe tiene que de alguna manera lidiar el manejo de turnos pero cómo lo hace no es algo de interés para la clase Empleado.
Otra alternativa también podría ser que la clase Empleado tenga un atributo que sea instancia de una clase que se encargue de manejar los llamados o la prohibición de llamados. Ese estado podría ser cambiado por el jefe a través de otros métodos:
public class Empleado { private TurnoDeLlamada turnoDeLlamada; public Empleado() { this.turnoDeLlamada = new TurnoLlamadasProhibidas(); } public void llamarA(Empleado otroEmpleado) { this.turnoDeLlamada.llamarA(otroEmpleado); } public void habilitarLlamadas() { this.turnoDeLlamada = new TurnoLlamadasPermitidas(); } public void deshabilitarLlamadas() { this.turnoDeLlamada = new TurnoLlamadasProhibidas(); } }
Esto tampoco es necesariamente mejor y también tiene sus ventajas y desventajas, pero se pueden probar y combinar varias ideas similares.
Saludos,
Tomás
Tomas,
gracias por la respuesta y todas las alternativas!
te consulto sobre uno de los ejemplos que diste pero por que tuvimos un problema similar con otro tema.
public void llamarA(Empleado otroEmpleado) { this.jefe.realizarLlamada(this, otroEmpleado); }esa opción que nos diste, se resolvería así?
Public class Empleado{
private Jefe jefe;
public void llamarA(Empleado otroEmpleado) { //Delega
this.jefe.realizarLlamada(this, otroEmpleado);
}
public void llamalo(Empleado otroEmpleado) { //hace la llamada //lo llama } }
Public class Jefe{
private TurnoLlamadas turnoLlamadas;
public void llamar (Empleado empleado, Empleado otroEmpleado){
empleado.llamarA(otroEmpleado)
}
public void realizarLlamada(Empleado unEmpleado, Empleado otroEmpleado){
turnoLlamdas.realizarLlamada (unEmpleado, otroEmpleado)
}
}
Public class TurnoLlamadasHabilidatas{
public void realizarLlamada (Empleado unEmpleado, Empleado otroEmpleado){
unEmpleado.llamalo (otroEmpleado)
}
}
Gracias,Saludos.
Hola José:
Sí, es una posibilidad. Aunque me parece que tiene demasiados idas y vueltas. Haría falta un diagrama de secuencia para aclararlo un poco pero, por lo que entiendo, tu secuencia empieza con el método public void llamar(Empleado empleado, Empleado otroEmpleado)
de la clase Jefe para que vaya a la clase Empleado, luego vuelva a la clase Jefe, luego a la clase Turno y finalmente de vuelta al Empleado. Me parece que tendría más sentido empezar la secuencia desde la clase Empleado y prescindir del primer método llamar de la clase Jefe. O, si quisieras empezar por el Jefe entonces no haría falta tantas visitas al Empleado. Esto también depende de qué significa la realización de una llamada en tu modelo.
Saludos,
Tomás