Mi jefe me dio un proyecto con una lógica particular. Tengo que desarrollar una página web que tenga que guiar al navegador a través de muchos casos hasta que llegue al producto.
Este es el esquema de ruta de navegación en el sitio:
¡IMPORTANTE!
En la página Productos, el navegador puede elegir qué filtro quiere.
- Si A, él / ella DEBE pasar por B (y luego C, por supuesto) o C y llegar a los productos.
- Si B, él / ella DEBE pasar por la C y alcanzar los productos.
- Si C, él / ella llega directamente a los productos.
Por supuesto, si empiezo desde AI sigo el camino más largo y cuando llego a mis productos tengo 3 filtros activos.
Hasta ahora desarrollé el siguiente código que funciona bien.
if filter_A
if filter_B
filter_C()
.. else ..
else
filter_C
.. else ..
else
if filter_B
filter_C()
.. else ..
else
filter_C()
.. else ..
Estoy aquí para preguntar qué habría hecho un programador más experto en esta situación. No respeté el principio DRY, no me gusta y me gustaría conocer una forma alternativa de desarrollar este tipo de lógica.
Pensé en dividir cada sección de código en funciones, pero ¿es una buena idea en este caso?
fuente
filter_C
, pero las declaraciones condicionales indican que el flujo de control puede dar la vueltafilter_C
. Esfilter_C
opcional?Respuestas:
No ha dicho si los filtros toman algún parámetro. Por ejemplo,
filter_A
podría ser un filtro de categoría, por lo que no es solo una cuestión de "¿Necesito aplicar?filter_A
", Podría ser "Necesito aplicarfilter_A
y devolver todos los registros con el campo de categoría =fooCategory
".La forma más sencilla de implementar exactamente lo que ha descrito (pero asegúrese de leer la segunda mitad de la respuesta a continuación) es similar a las otras respuestas, pero no tendría ninguna verificación booleana. Yo definiría interfaces:
FilterA, FilterB, FilterC
. Entonces puedes tener algo como (soy un programador de Java, así que esta será una sintaxis de Java-esque):Entonces podría tener algo como esto (usando el patrón enton singleton de Effective Java ):
Pero si realmente desea que se filtren algunos elementos, puede proporcionar una instancia de una
FilterA
implementación que realmente haga algo. Su método de filtración será muy simple.Pero recién estoy comenzando.
Sospecho que la
applyFilter
llamada en realidad será bastante similar para los tres tipos de filtros. Si ese es el caso, ni siquiera lo haría de la manera descrita anteriormente. Puede obtener un código aún más limpio con solo una interfaz y luego hacer esto:Luego, a medida que su usuario navega por las páginas, simplemente agrega una nueva instancia de cualquier filtro que necesite cuando sea apropiado. Esto le permitirá poder aplicar múltiples instancias del mismo filtro con diferentes argumentos si necesita ese comportamiento en el futuro, y también agregar filtros adicionales en el futuro sin tener que cambiar su diseño .
Además, puede agregar algo como lo
NoOpFilter
anterior o simplemente no puede agregar un filtro en particular a la lista, lo que sea más fácil para su código.fuente
Filter
comoPredicate
entonces, podría usarlo directamente en laStream
API. Muchos lenguajes tienen construcciones funcionales similares.En este caso, es importante separar la lógica del filtrado y el flujo de control de cómo funcionan los filtros. La lógica del filtro debe separarse en funciones individuales, que pueden ejecutarse de forma independiente entre sí.
En el código de ejemplo publicado, hay 3 booleanos
filter_A
,filter_B
yfilter_C
. Sin embargo, desde el diagrama,filter_C
siempre se ejecuta, por lo que se puede cambiar a un incondicional.NOTA: Supongo que el diagrama de flujo de control es correcto. Existe una discrepancia entre el código de muestra publicado y el diagrama de flujo de control.
Un código separado controla qué filtros se ejecutan
Existe una separación clara entre controlar qué filtros se ejecutan y qué hacen los filtros. Romper esas dos piezas de lógica aparte.
fuente
Supongo que quiere el algoritmo más simple y claro.
En este caso, sabiendo que el filtro c siempre se aplica, lo viviría de la lógica if y lo aplicaría al final independientemente. Como se ve en su diagrama de flujo, cada filtro antes de c es opcional, porque cada uno de ellos puede aplicarse o no. En este caso, viviría ifs separados de cada filtro, sin anidar y encadenar:
si tiene un diagrama de flujo con un número variable de filtros, antes del obligatorio, en su lugar, guardaría todos los filtros en una matriz, en el orden en que deberían aparecer. Luego, procese filtros opcionales en el bucle y aplique el obligatorio al final, fuera del bucle:
o:
de origen, tendría que definir la subrutina de procesamiento de filtro.
fuente
Asumiré que filterA, filterB y filterC realmente modifican la lista de productos. De lo contrario, si son solo verificaciones si, entonces se pueden ignorar filterA y filterB ya que todas las rutas conducen finalmente a filterC. Su descripción del requisito parece implicar que cada filtro reducirá la lista de productos.
Asumiendo que los filtros realmente reducen la lista de productos, aquí hay un poco de pseudocódigo ...
En sus requisitos, filterC no se aplica automáticamente, pero en el diagrama sí. Si el requisito es que al menos filterC se debe aplicar sin importar qué, entonces llamaría a applyFilter (filterC, productos) sin verificar si se elige filterC.
fuente
Me pregunto si modelar sus filtros para que sea algún tipo de objeto en un gráfico tendría sentido. Al menos eso es lo que pienso cuando veo el diagrama.
Si modela la dependencia de los filtros como un gráfico de objeto, entonces el código que maneja las posibles rutas de flujo es bastante sencillo sin ninguna lógica complicada. Además, el gráfico (lógica de negocios) puede cambiar, mientras que el código que interpreta el gráfico permanece igual.
fuente