Patrones de diseño de estrategia en Kotlin | de Abhishek Saxena | agosto 2022

Foto de Kenny Eliason en UnsplashAntes de comprender el patrón de diseño de estrategia, debe comprender qué son los patrones de diseño y por qué los necesitamos en primer lugar.

Los patrones de diseño son la solución a los problemas más comunes en el diseño de software.

¿No son geniales ya que son las soluciones a problemas comunes? ¿Significa esto que son la bala de plata y pueden estar en cualquier lugar? La respuesta es no, no pueden. En el mundo real, necesita aprender e inspirarse en estas soluciones para resolver su problema, pero lo ayudan a diseñar su solución. La intención y el enfoque de un patrón de diseño lo ayudan a resolver el problema en cuestión lo mejor que puede, o es posible que no necesite cambiar el patrón de diseño para lograr la solución. Ahora, llegando al patrón de diseño de estrategia, ¿qué es y por qué lo necesitamos?

El patrón de diseño de estrategia es un patrón que usamos para encapsular una familia de algoritmos y hacerlos intercambiables.

El patrón de estrategia se basa en un principio de diseño muy importante, a saber Identifique los diferentes aspectos y sepárelos de lo que permanece igual.¿Entonces que significa eso? Tomemos 3 problemas diferentes y resolvámoslos con el patrón de estrategia.

  • Algoritmo de clasificación (capa de dominio)
  • Múltiples fuentes de datos (capa de datos: falsa/local/remota)
  • Estrategia de OnClick Listener (capa de interfaz de usuario: única/múltiple)

En este problema, tenemos dos o más algoritmos de clasificación y podemos decidir cuál usar en función de la entrada del usuario. En aras de la simplicidad, supongamos que tenemos dos algoritmos, Bubble Sort y Merge Sort.El código anterior es una implementación simple de cómo podemos usar un algoritmo de clasificación diferente según la entrada del usuario. Si observa cuidadosamente que a medida que agregamos o eliminamos algoritmos de clasificación, debemos actualizar la escalera Else-if para reflejar los cambios.Así que puedo decir que el bloque de escalera Else-If es la pieza de código que varía.Según el principio, tenemos que encapsular lo que varía.Ahora, cuando necesitamos agregar/eliminar un algoritmo, agregamos otra declaración al bloque when y agregamos el método que contiene el algoritmo de clasificación. Debe actualizar el bloque when para ejecutar el algoritmo seleccionado. Al evaluar los métodos de los algoritmos, se da cuenta de que son prácticamente iguales, ya que ambos toman una matriz de números como entrada, tienen un cuerpo con la implementación del algoritmo y no tienen tipo de retorno. Esto significa que podemos extraer los métodos en una interfaz, digamos SortStrategy, y cada implementación de la interfaz tendrá el algoritmo de clasificación correspondiente.Podemos usar esta interfaz y pasarla como argumento al método de clasificación en el controlador.Con la interfaz, eliminamos por completo las declaraciones condicionales para elegir el algoritmo de clasificación utilizado para clasificar los números. Supongamos que queremos agregar/eliminar un algoritmo de clasificación z y pasarlo al método de clasificación. Ahora pasamos el algoritmo de clasificación junto con los números para ordenarlos. Hemos encapsulado la familia de algoritmos, aquí algoritmos de clasificación, y los hemos hecho intercambiables.bonificación🎉: Todos hemos usado Principios SÓLIDOS en el ejemplo anterior. En este enunciado del problema, tenemos un repositorio que es responsable de almacenar los datos del usuario y queremos probar el repositorio. Un UserRepository simple con el método de guardar se vería así.Debido a que la llamada a la API para salvar al usuario reside directamente en el repositorio, es difícil probar el código de forma aislada con los resultados falsos o simulados de la llamada a la API. Esto significa que no podemos probar correctamente el UserRepository. En el ejemplo anterior, el código varía en save(), la llamada API real para los datos reales y la implementación simulada/falsa para la prueba. Esto significa que el código en el método save() varía. Ahora que hemos identificado la parte variable, necesitamos encapsularla y hacerla intercambiable. Vamos a crear una interfaz UserDataSource que encapsule el bloque de código variable.Ahora podemos usar estas fuentes de datos en UserRepository, y la implementación de la fuente de datos define su comportamiento.El método del controlador sería: usando el patrón de estrategia, podemos cambiar fácilmente entre las diferentes fuentes de datos, remotas y falsas. Este enfoque incluso se puede usar si no tiene las API listas pero desea trabajar con fuentes de datos locales. Simplemente cree una implementación con los datos locales o codificados, asígnele el nombre LocalUserDataSource y páselo al UserRepository hasta que las API estén listas. En esta declaración del problema, tenemos un botón en la interfaz de usuario y queremos establecer dinámicamente la cantidad de veces que el usuario debe hacer clic en el botón para realizar la operación. Número posible de clics

  • Ninguno (el botón está deshabilitado)
  • único
  • Múltiple (el número de clics puede ser fijo o aleatorio dentro de un rango)

Vamos a burlarnos de un botón.La operación que queremos realizar cuando se hace clic en el botón. El controlador para mostrar la operación de clic y configurar el botón sin un patrón de estrategia sería. Como puede ver, el botón de un solo clic es bastante simple y podemos crear fácilmente tantos como queramos. Sin embargo, los botones de varios clics no son tan fáciles de crear porque necesitamos replicar la lógica de varios clics cada vez que queremos crear un botón de este tipo. ¿Qué pasa si queremos crear un botón con múltiples clics, pero la cantidad de clics debe estar aleatoriamente en un cierto rango de números? Esto agregaría complejidad al mismo tiempo que crearía un botón que ya era difícil para empezar.Entonces podemos decir que la parte que varía en este enunciado del problema es la cantidad de clics que se necesitan para realizar la operación.Para resolver esto, creamos OnClickStrategy y tenemos varias implementaciones para diferentes números de clics.SingleOnClickStrategyMutlipleOnClickStrategyTambién necesitaríamos un ButtonItem para almacenar la estrategia para el botón. Supongamos que está utilizando un marco de interfaz de usuario basado en componentes: Flutter, React o Jetpack Compose de Android.Estoy usando Jetpack Compose de Android para este ejemplo, pero lo mismo se puede replicar en los otros marcos.UIButton Composable ViewModel y Screen ComposableNota: El comportamiento de clic del usuario se simula con el bloque también. Usamos varias estrategias para los botones de la interfaz de usuario y estas estrategias se pueden agregar a cualquier botón en la pantalla sin duplicar el código para el comportamiento onClick.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.