Introducción
Estoy implementando una clase Java abstracta de un marco de procesamiento *. Al implementar la función execute
, puedo agregar funcionalidad lógica de negocios. Me gustaría agregar el registro al inicio y al final de cada implementación de cada una de mis funciones de ejecución. También entre algunos registros, si se hacen cosas específicas. Sin embargo, me gustaría hacer esto de manera uniforme. Mi pensamiento era heredar la clase de marco a una nueva clase propia que implemente el registro y proporcione algunas executeWithLogging
funciones nuevas , que están envolviendo el registro alrededor de las partes específicas. No estoy seguro de si esa es la mejor idea y si puedo usar un patrón de diseño que haga que todo el esfuerzo sea elegante. ¿Cómo seguiría con todo el asunto?
Desafíos (¡ten en cuenta estos!)
- Un desafío en mi caso es que la clase original tiene solo una
execute
función, sin embargo, necesitaría iniciar sesión en varias partes. - La segunda cosa es: usar un patrón de decorador (también fue mi primera idea) no funciona del todo, si estoy usando también un
execute
, porque lasuper.execute()
función debería llamarse en la primera línea de mi nuevoexecute()
, ¿no? ? - Habría al menos 4 clases involucradas:
BaseFunction
del marco,LoggingFunction extends BaseFunction
de mí,MyBusinessFunction extends LoggingFunction
de mí,MyBusinessClass
que instanciaMyBusinessFunction
. - No solo necesito iniciar sesión al principio y al final
execute
, sino también en el medio. - El "registro" no es solo un simple registro de Java, sino que en realidad se registra en una base de datos. Esto no cambia nada acerca de los principios, pero demuestra que el registro puede ser más que una sola línea de código.
Tal vez un ejemplo de cómo lo haría todo sería bueno, para ponerme en marcha.
| * Una función Tridente de tormenta, similar a un rayo de tormenta, pero esto no es particularmente importante.
fuente
execute
enBaseFunction
abstracto?execute
es abstracto enBaseFunction
.Respuestas:
En general, hay varias formas posibles de realizar el registro en torno a una determinada ejecución. En primer lugar, es bueno que desee separar esto, ya que el registro es un ejemplo típico de Separación de preocupaciones . Realmente no tiene mucho sentido agregar el registro directamente en la lógica de su negocio.
En cuanto a los posibles patrones de diseño, aquí hay una lista (no concluyente) desde la parte superior de mi cabeza:
Patrón de decorador : un patrón de diseño bien conocido, en el que básicamente envuelve la clase sin registro en otra clase de la misma interfaz y el contenedor realiza el registro antes y / o después de llamar a la clase ajustada.
Composición de funciones : en un lenguaje de programación funcional, simplemente puede componer su función con una función de registro. Esto es similar al patrón decorador en lenguajes OO, pero no es una forma preferida realmente, ya que la función de registro compuesta se basaría en una implementación de efectos secundarios.
Mónadas : las mónadas también son del mundo de la programación funcional y le permiten desacoplar su ejecución y registro. Básicamente, esto significa que agrega los mensajes de registro necesarios y los métodos de ejecución, pero aún no se ejecuta. Luego puede procesar la mónada para realizar la escritura de registros y / o la ejecución real de la lógica de negocios.
Programación orientada a aspectos : enfoque más sofisticado, que logra una separación completa, ya que la clase que realiza el comportamiento sin registro nunca interactúa directamente con el registro.
Retransmisión: otros patrones de diseño estándar también pueden ser adecuados, por ejemplo, una Fachada podría servir como punto de entrada registrado, antes de reenviar la llamada a otra clase que realiza la parte de lógica de negocios. Esto también se puede aplicar a diferentes niveles de abstracción. Por ejemplo, puede registrar las solicitudes realizadas en una URL de servicio externamente accesible, antes de retransmitirlas a una URL interna para el procesamiento real no registrado de las solicitudes.
En cuanto a su requisito adicional de que necesita realizar el registro "en el medio", eso probablemente apunta a un diseño extraño. ¿Por qué es que su ejecución está haciendo tanto, que algo como un "medio" de su ejecución es remotamente interesante? Si de hecho hay tantas cosas sucediendo, ¿por qué no agruparlas en etapas / fases / qué-tienes? Supongo que, en teoría, podría lograr iniciar sesión en el medio con AOP, pero aún argumentaría que un cambio de diseño parece ser mucho más apropiado.
fuente
Tengo la sensación de que absolutamente quieres usar un patrón. Recuerde que un mal uso de los patrones de diseño puede resultar en un código menos mantenible / legible.
Ese sonido dijo ...
Su caso es complicado, ya que parece que desea hacer 2 tipos de registro:
execute
)execute
)Para el primer caso, en el momento en que desea registrar algunas cosas dentro de una función, debe hacerlo ... dentro de la función. Podría usar el patrón de método de plantilla para hacer las cosas un poco más bonitas, pero creo que es excesivo en este caso.
Para el segundo caso, el patrón decorador es el camino a seguir:
Y podría usarlo así en
BusinessClass
:Una llamada a
doFunction
registrará esto:fuente
super.execute();
lugar deorigin.execute();
?super.execute()
como este método esabstract
?Su enfoque parece válido y en realidad es una implementación del Patrón Decorador . Supongo que hay otras formas de hacerlo, pero Decorator es un patrón muy elegante y fácil de entender que es muy adecuado para resolver su problema.
fuente
¿Qué hay de usar el patrón de comando?
fuente
execute()
haga nada por el momento, ya que solo está instanciandoMyLoggingCommandWhole
.MyLoggingCommandWhole
,executeWithoutLogging();
desde la ejecución , se ejecutaMyLoggingCommandWhole
. No es ese el caso?MyLoggingCommandWhole cmd = new MyLoggingCommandWhole() { ... }; cmd.executeWithoutLogging();
executeWithLogging()
ycmd.executeWithLogging()
. Después de todo, eso es lo que debería ejecutarse.