Como devo criar uma interface combinada para dois módulos logicamente independentes?

5

Estou tendo problemas para criar uma boa maneira de estruturar as interfaces para dois módulos que são logicamente independentes, mas cujas implementações podem ser combinadas para fins de desempenho ou eficiência.

Minha situação específica é a substituição dos módulos separados de enfileiramento e registro em um aplicativo de roteamento de mensagens por uma implementação combinada com base em banco de dados (vamos chamá-lo de DbQueueLog ). É muito fácil para DbQueueLog implementar as interfaces IQueue e ILogger para que os clientes dos antigos módulos de enfileiramento e registro possam usá-la de maneira integrada. O desafio é que a implementação mais eficiente e eficiente de DbQueueLog envolve a combinação dos métodos EnqueueMessage(Message m) e LogMessage(Message m, List<LogParams> p) em um método EnqueueAndLogMessage(Message m, List<LogParams> p) que minimiza o número de chamadas do banco de dados entre processos e a quantidade de dados gravados no disco. Eu poderia criar uma nova interface IQueueLog com esses novos métodos, mas estou desconfortável com o que isso significaria se uma iteração futura do aplicativo fosse movida de volta para os módulos de enfileiramento e registro em separado.

Existe alguma abordagem de design para essa situação que me permita construir a implementação eficiente% performance DbQueueLog agora sem juntar permanentemente os módulos de log e enfileiramento do aplicativo?

Editar: o aplicativo é criado no Windows usando C # no caso de existirem quaisquer técnicas específicas da plataforma que possam estar disponíveis.

    
por Dan 23.09.2013 / 16:07
fonte

3 respostas

1

Parece que o EnqueueAndLogMessage é um serviço bastante típico. Minha sugestão é expor uma interface para EnqueueAndLogMessage. Em seguida, na implementação concreta do serviço, use duas variáveis de instância para suas interfaces EnqueueMessage e LogMessage. Isso permitirá que você forneça um serviço que lide com os recursos de criação de registros e log, sem vinculá-lo à implementação de nenhum deles. Se você não precisar mais do serviço combinado, é tão simples quanto chamar um serviço diferente.

código Psuedo:

Interface EnqueueAndLogMessageService {
   public void queAndLogMessage(Message message);
}

Class EnqueueAndLogMessageServiceImpl {
   EnqueueMessage enqueueMessageSvc;
   LogMessage logMessageSvc;

   public void queAndLogMessage(Message message) {
      enqueueMessageSvc.queMessage(message);
      logMessageSvc.logMessage(message);
   }
}
    
por 25.09.2013 / 02:38
fonte
1

Se eles são módulos logicamente independentes que compartilham em parte uma implementação comum, você deve não criar uma interface combinada para eles, porque irá assombrá-lo se você decidimos usar implementações separadas novamente.

Por outro lado, você mencionou que um dos módulos é um módulo de log.
Se todas as chamadas para IQueue devem (idealmente) ser acompanhadas por uma chamada correspondente para o registrador, você pode decidir colocar essa responsabilidade com a implementação de IQueue . Uma função pode chamar EnqueueMessage e obter esse evento registrado ao mesmo tempo sem nenhum esforço.

Dessa forma, você pode usar sua implementação otimizada agora e, se precisar dividi-los, poderá fazer isso sem afetar os usuários de IQueue e do criador de logs.

Se a interface de log usar parâmetros adicionais para os quais não há um padrão razoável e o valor também não puder ser deduzido dos argumentos existentes para o método IQueue , deve ficar claro que adicionar a responsabilidade de executar o logging para a implementação IQueue pode significar que você tenha que mudar a interface de alguns (ou todos) os métodos IQueue .

    
por 23.09.2013 / 19:51
fonte
1

Eu vejo dois casos aqui que poderiam ser aplicáveis à situação que requer abordagens diferentes.

EnqueueMessage é um caso especial de LogMessage

Não é totalmente claro a partir da mensagem, mas parece que se você estiver disposto a combinar EnqueueMessage e LogMessage em uma única função que EnqueueMessage é simplesmente um caso especial (nulo "p") do LogMessage. Se esse for o caso, em vez de combinar interfaces, eu as manteria separadas e usaria a composição a seu favor. Nesse caso, o ILogger seria um membro da classe que implementa o IQueue. O método EnqueueMessage simplesmente usaria a instância do ILogger e chamaria seu método LogMessage. Se no futuro a implementação de uma classe IQueue tivesse que mudar, você simplesmente não instanciaria mais um ILogger.

EnqueueMessage contém funcionalidades diferentes, em seguida, LogMessage

Nesse caso, recomendo veementemente que sejam classes separadas e não tenham uma interface combinada. Se eles realmente têm uma funcionalidade diferente, então, combinando-os, você está quebrando o encapsulamento e criando códigos difíceis de manter. Dito isso, você precisa equilibrar a capacidade de manutenção com o desempenho. Só tome cuidado para não superestimar o ganho de eficiência de combinar a implementação. Construa os dois caminhos e meça a diferença para que você possa tomar uma decisão informada.

    
por 25.09.2013 / 21:44
fonte