Padrão de Design - DLL por Estratégia

8

Normalmente, eu me via projetando meu aplicativo da seguinte maneira:

  1. Uma DLL contendo interfaces para um subsistema desejado. Por exemplo Company.Framework.Persistence.dll,.
  2. Uma nova DLL por cada estratégia (ou implementações ) do referido subsistema. Por exemplo:
    • Company.Framework.Persistence.MSSQL.dll
    • Company.Framework.Persistence.MySQL.dll
    • Company.Framework.Persistence.FileSystem.dll

Isso resultará em uma solução muito grande com muitos projetos, mas, por outro lado, daria ao consumidor a chance de escolher a DLL apropriada para suas necessidades.

Se tivéssemos uma única DLL chamada Company.Framework.Persistence.dll, o consumidor teria que carregar muitas estratégias que ele talvez nunca usasse. Ter uma DLL modularizada resolveria esse problema.

Esta é uma boa prática? Existe uma desvantagem com esse design?

Matias Cicero
fonte
1
Existe uma desvantagem em incluir tudo? Armazenamento no computador é barato . Enquanto a complexidade para o usuário for baixa, isso realmente importa?
2
Você sempre pode mesclar todos os assemblies em uma mega-DLL como uma etapa de compilação: stackoverflow.com/questions/8077570/…
Den
relacionados (abordagem semelhante): codeproject.com/Articles/666492/Dynamic-Load-NET-Assembly
Nick Alexeev

Respostas:

3

Penso que as vantagens desta abordagem superam em muito as desvantagens.

O que você está conseguindo aqui é mais minério menos um perfeito "implementação" do Ina SOLIDpor meio do Stairwaypadrão - ou seja, sua aplicação depende "para baixo" em uma interface definida no Company.Framework.Persistence.dlle as próprias implementações individuais também dependem "para cima" nessa abstração.

Isso significa que seu aplicativo está altamente dissociado de todos os detalhes da implementação (é claro que você normalmente desejará compor o gráfico de tempo de execução real usando algum tipo de container IOC). Eu vinculei descaradamente a uma imagem existente desse padrão a partir de outra resposta sobre o assunto. no estouro de pilha:

Exemplo de padrão de escada

No livro Código Adaptativo via C #, o autor fala sobre essa abordagem e a chama especificamente de algo que sempre deve ser feito, pois fornece um nível tão alto de dissociação. ( exemplo )

Outra vantagem possível é poder consertar implementações individuais sem se preocupar com o fato de você ter afetado outras pessoas, embora essa seja bastante pequena depois de ter sido diligente com seus testes de regressão; também poder implantar implementações individuais em subpastas, que também podem conter versões específicas de quaisquer dependências de terceiros de que possam precisar, provavelmente ajudará a manter as coisas bem organizadas.

A única desvantagem real que consigo pensar com essa abordagem é que é possível, em teoria, alterar a interface Company.Framework.Persistence.dll(junto com os binários do aplicativo) e deixar de atualizar as dlls de implementação correspondentes, o que levará a erros de tempo de execução para os usuários.

Tendo sido culpado de fazer exatamente isso no passado, posso dizer que isso é realmente apenas algo que pode acontecer se você for muito descuidado :)

Stephen Byrne
fonte
1

Eu faço assim também.

Os projetos / dlls são essencialmente gratuitos e tornam o código mais legível e fácil de usar.

Conheço pessoas que usam uma única DLL grande e diferenciam-se com espaços de nome. Mas como você diz que eles precisam implantar código não utilizado, não vejo nenhum benefício para a prática e muitas desvantagens, como

  • mudar para uma implementação requer recompilar outras
  • código não utilizado é implantado para viver (risco de bugs)
  • o código de teste é implantado ao vivo (zombarias, etc., risco de erros, configuração incorreta)
  • código obsoleto requer refatoração para remover (digamos que não usamos mais o MySQL)
  • precisa testar o código não utilizado antes da implantação (estamos testando certo?)
  • refatoração pode causar erro de compilação no componente não utilizado (digamos que alteramos uma interface)

Posso cortar custos e colocar a implementação concreta com a interface para pequenas aplicações, se evitar um projeto que contenha apenas uma única interface. Mas normalmente acho que as interfaces vão com os modelos. Então eu teria

  • Company.Framework.Models.dll (inclui interface para persistência)
  • Company.Framework.Persistence.MySQL.dll (ref Models, mas precisa de qualquer maneira)
  • Company.Framework.Persistence.Mock.dll (ref Models, mas precisa de qualquer maneira)

ou (atalho incorreto!)

  • Company.Framework.Models.dll (não incluindo interfaces)
  • Company.Framework.Persistence.MySQL.dll (inclui interface de persistência, modelos de referência)
  • Company.Framework.Persistence.Mock.dll (modelos de referência e sql, mas não está implantado para viver)

Obvs, é muito simples refatorar as interfaces se o aplicativo aumentar em tamanho / complexidade

Ewan
fonte
0

A vantagem da estratégia dois é minimizar o dll hell.

Geralmente Company.Framework.Persistence.MySQL.dll dependerá de alguma dll para interface com o MySql. Se eu não tenho interesse no MySql, por que devo baixar a dll do MySql?

Digamos que sua estrutura tenha suporte para 20 provedores de armazenamento diferentes. A maioria dos usuários usa apenas um. Portanto, todos os usuários precisam obter 19 DLLs que nunca usarão apenas para compilar sua estrutura.

Seguindo a estratégia dois, você permite que os usuários instalem apenas as dlls que vão usar e, assim, minimizando o inferno da dll.

Esben Skov Pedersen
fonte