Introdução
Estou implementando uma classe Java abstrata de uma estrutura de processamento *. Ao implementar a função execute
, sou capaz de adicionar funcionalidade lógica de negócios. Gostaria de adicionar o registro no início e no final de cada implementação de todas as minhas funções de execução. Também entre alguns logs, se coisas específicas forem feitas. No entanto, eu gostaria de fazer isso de maneira uniforme. Meu pensamento era herdar a classe de estrutura para uma nova classe que implementa o log e fornece algumas novas executeWithLogging
funções, que estão envolvendo o log em partes específicas. Não tenho certeza se essa é a melhor ideia e se posso usar um padrão de design que tornaria todo o empreendimento elegante. Como eu continuaria com a coisa toda?
Desafios (considere estes!)
- Um desafio no meu caso é que a classe original tem apenas uma
execute
função; no entanto, eu precisaria registrar várias partes. - A segunda coisa é: Usar um padrão decorador (também foi minha primeira ideia) não funciona muito bem, se eu estiver usando também um
execute
, porque asuper.execute()
função-teria que ser chamada na primeira linha do meu novoexecute()
, não é? ? - Haveria pelo menos 4 classes envolvidas:
BaseFunction
da estrutura,LoggingFunction extends BaseFunction
de mim,MyBusinessFunction extends LoggingFunction
de mim,MyBusinessClass
que instanciaMyBusinessFunction
. - Não só preciso fazer logon no início e no final de
execute
, mas também no meio. - O "registro" não é apenas o registro Java simples, mas o registro em um banco de dados. Isso não muda nada sobre os princípios, mas demonstra que o log pode ser mais do que apenas uma linha de código.
Talvez um exemplo de como eu faria a coisa toda seria legal, para eu continuar.
| * Uma função Storm Trident, semelhante a um parafuso Storm, mas isso não é particularmente importante.
fonte
execute
emBaseFunction
abstrato?execute
é abstrato emBaseFunction
.Respostas:
Geralmente, existem várias maneiras possíveis de executar o log em torno de uma determinada execução. Antes de tudo, é bom que você queira separar isso, pois o log é um exemplo típico de Separação de preocupações . Realmente não faz muito sentido adicionar logs diretamente à sua lógica de negócios.
Quanto aos possíveis padrões de design, aqui está uma lista (não conclusiva) do topo da minha cabeça:
Padrão do decorador : um padrão de design conhecido, no qual você basicamente agrupa a classe não registrada em outra classe da mesma interface e o wrapper faz o log antes e / ou depois de chamar a classe agrupada.
Composição da função : Em uma linguagem de programação funcional, você pode simplesmente compor sua função com uma função de registro. Isso é semelhante ao padrão decorador nas linguagens OO, mas na verdade não é uma maneira preferida, uma vez que a função de log composta seria baseada em uma implementação de efeito colateral.
Mônadas : as mônadas também são do mundo da programação funcional e permitem desacoplar sua execução e registro. Isso basicamente significa que você agrega as mensagens de log e os métodos de execução necessários, mas ainda não os executa. Em seguida, você pode processar a mônada para executar a gravação de log e / ou a execução real da lógica de negócios.
Programação orientada a aspectos : abordagem mais sofisticada, que obtém separação completa, pois a classe que faz o comportamento de não registrar nunca interage diretamente com o registro.
Retransmissão: Outros padrões de design padrão também podem ser adequados, por exemplo, uma Fachada pode servir como ponto de entrada registrado, antes de encaminhar a chamada para outra classe que executa a parte da lógica de negócios. Isso também pode ser aplicado a diferentes níveis de abstração. Por exemplo, você pode registrar solicitações feitas em um URL de serviço alcançável externamente, antes de retransmitir para um URL interno para processamento real não solicitado de solicitações.
Quanto ao requisito adicional de que você precisa executar o registro "no meio" - isso provavelmente está apontando para um design estranho. Por que sua execução está fazendo tanto, que algo como um "meio" de sua execução é remotamente interessante? Se realmente existem tantas coisas acontecendo, por que não agrupá-las em etapas / fases / o que você tem? Em teoria, você poderia logar no meio com a AOP, mas ainda assim argumentaria que uma alteração no design parece ser muito mais apropriada.
fonte
Tenho a sensação de que você deseja absolutamente usar um padrão. Lembre-se de que um mau uso de padrões de design pode resultar em um código menos sustentável / legível.
Isso sendo dito ...
Seu caso é complicado, pois parece que você deseja fazer dois tipos de registro:
execute
)execute
)Para o primeiro caso, no momento em que você deseja registrar algumas coisas dentro de uma função, você deve fazê-lo ... dentro da função. Você pode usar o padrão do método template para tornar as coisas um pouco mais bonitas, mas acho que é um exagero nesse caso.
Para o segundo caso, o padrão do decorador é o caminho a seguir:
E você pode usá-lo assim em
BusinessClass
:Uma chamada para
doFunction
registrará isso:fonte
super.execute();
vez deorigin.execute();
?super.execute()
como é esse métodoabstract
?Sua abordagem parece válida e é realmente uma implementação do Padrão Decorador . Suponho que há outras maneiras de fazer isso, mas o Decorator é um padrão muito elegante e fácil de entender que é muito adequado para resolver seu problema.
fonte
Que tal usar o Padrão de Comando?
fonte
execute()
não faça nada no momento, pois você está apenas instanciandoMyLoggingCommandWhole
.MyLoggingCommandWhole
, executa aexecuteWithoutLogging();
partir deMyLoggingCommandWhole
. Não é esse o caso?MyLoggingCommandWhole cmd = new MyLoggingCommandWhole() { ... }; cmd.executeWithoutLogging();
executeWithLogging()
ecmd.executeWithLogging()
. Afinal, é isso que deve ser executado.