Considere dos clases Dog
y Cat
ambas conforme al Animal
protocolo (en términos del lenguaje de programación Swift. Esa sería la interfaz en Java / C #).
Tenemos una pantalla que muestra una lista mixta de perros y gatos. Hay una Interactor
clase que maneja la lógica detrás de escena.
Ahora queremos presentar una alerta de confirmación al usuario cuando quiera eliminar un gato. Sin embargo, los perros deben eliminarse inmediatamente sin ninguna alerta. El método con condicionales se vería así:
func tryToDeleteModel(model: Animal) {
if let model = model as? Cat {
tellSceneToShowConfirmationAlert()
} else if let model = model as? Dog {
deleteModel(model: model)
}
}
¿Cómo se puede refactorizar este código? Obviamente huele
fuente
Dog
, yCat
se describen como clases, mientras queAnimal
es un protocolo que se implementa por cada una de esas clases. Así que hay un poco de desajuste entre la pregunta y su respuesta.Interactor
estado ahoraCat
yDog
se manejan, que puede y debe ser una característica común enAnimal
. Hacer cualquier otra cosa es pedir un dolor de cabeza de mantenimiento más tarde.Tell vs. Ask
El enfoque condicional que está mostrando lo llamaremos " preguntar ". Aquí es donde el cliente consumidor pregunta "¿de qué tipo eres?" y personaliza su comportamiento e interacción con los objetos en consecuencia.
Esto contrasta con la alternativa que llamamos " tell ". Usando tell , llevas más trabajo a las implementaciones polimórficas, de modo que el código del cliente consumidor sea más simple, sin condicionales y común, independientemente de las posibles implementaciones.
Como desea utilizar una alerta de confirmación, puede hacer que sea una capacidad explícita de la interfaz. Por lo tanto, puede tener un método booleano que opcionalmente verifica con el usuario y devuelve la confirmación booleana. En las clases que no quieren confirmar, simplemente anulan con
return true;
. Otras implementaciones pueden determinar dinámicamente si desean usar la confirmación.El cliente consumidor siempre usaría el método de confirmación independientemente de la subclase particular con la que esté trabajando, lo que hace que la interacción diga en lugar de preguntar .
(Otro enfoque sería enviar la confirmación a la eliminación, pero eso sorprendería a los clientes consumidores que esperan que una operación de eliminación tenga éxito).
fuente
Interactor
estado ahoraDeterminar si se necesita una confirmación es responsabilidad de la
Cat
clase, así que habilítelo para realizar esa acción. No conozco a Kotlin, así que expresaré las cosas en C #. Esperemos que las ideas sean transferibles a Kotlin también.Luego, al crear una
Cat
instancia, debe proporcionarlaTellSceneToShowConfirmationAlert
, que deberá devolvertrue
si está bien para eliminar:Y luego tu función se convierte en:
fuente
Cat
clase. Yo diría que ahí es donde pertenece. No puede decidir cómo se logra esa confirmación (que se inyecta) y no se elimina a sí misma. Entonces no, no mueve la lógica de eliminación al modelo.TellSceneToShowConfirmationAlert
en una instancia deCat
. En situaciones donde eso no es fácil (como en un sistema de varias capas donde esta funcionalidad se encuentra en un nivel profundo), entonces este enfoque no sería bueno.Yo recomendaría ir por un patrón de visitante. Hice una pequeña implementación en Java. No estoy familiarizado con Swift, pero puedes adaptarlo fácilmente.
El visitante
Su modelo
Llamando al visitante
Puede tener tantas implementaciones de AnimalVisitor como desee.
Ejemplo:
fuente