Considere estes métodos:
public List<Employee> GetAllEmployees()
{
using (Entities entities = new Entities())
{
return entities.Employees.ToList();
}
}
public List<Job> GetAllJobs()
{
using (Entities entities = new Entities())
{
return entities.Jobs.ToList();
}
}
public List<Task> GetAllTasksOfTheJob(Job job)
{
using (Entities entities = new Entities())
{
return entities.Tasks.Where(t => t.JobId == job.Id).ToList();
}
}
Usar bloco é o mesmo e foi repetido 3 vezes aqui (é claro, mais de 100 vezes no aplicativo real). Como é possível implementar o princípio DRY (Don't Repeat Yourself) para o using
bloco? É considerado uma violação do principal DRY?
Atualização: não estou falando sobre o que foi implementado dentro do using
bloco. O que eu realmente quero dizer aqui é o using (Entities entities = new Entities())
. Esta linha é repetida 100 vezes ou mais.
c#
design-patterns
dry
Saeed Neamati
fonte
fonte
Respostas:
Uma idéia seria envolvê-lo com uma função que leva a
Func
.Algo assim
Então o seu código acima se torna
Também fiz
Entities
um parâmetro de tipo, porque estou assumindo que você tem mais de um tipo com o qual está fazendo isso. Caso contrário, você pode removê-lo e apenas usar o parâmetro param para o tipo de retorno.Para ser sincero, esse tipo de código não ajuda na legibilidade. Na minha experiência, os colegas de trabalho Jr também enfrentam dificuldades.
Atualizar Algumas variações adicionais nos ajudantes que você pode considerar
fonte
Entities
.IEnumerable
fora da função caso houvesse alguma não-IEnumerable
propriedade de T que o chamador quisesse retornar, mas você está certo, isso o limparia um pouco. Talvez seja bom ter um ajudante para os solteiros e osIEnumerable
resultados. Dito isto, eu ainda acho que retarda o reconhecimento de que o código faz, especialmente para alguém que não está acostumado a usar lotes de genéricos e lambdas (por exemplo, seus colegas de trabalho que não estão no SO :))WithEntities
, use emFunc<T,IEnumerable<K>>
vez deFunc<T,K>
e atribua a "WithEntities" um nome melhor (como SelectEntities). E eu não acho que "Entidades" precise ser um parâmetro genérico aqui.where T : IDisposable, new()
, conformeusing
necessárioIDisposable
para funcionar.Para mim, isso seria como se preocupar em procurar a mesma coleção várias vezes: é apenas algo que você precisa fazer. Qualquer tentativa de abstraí-lo tornaria o código muito menos legível.
fonte
foreach
coleção estiver muito grande ou se a lógica noforeach
loop estiver demorando, por exemplo. Um lema que tem vindo a adotar: Não obsess mas sempre estar atento a sua abordagemParece que você está confundindo o princípio "Uma vez e apenas uma vez" com o princípio DRY. O princípio DRY afirma:
No entanto, o princípio Uma vez e Somente uma vez é um pouco diferente.
O princípio DRY é geralmente usado no contexto da lógica real, não tão redundante usando instruções:
Fonte
fonte
Não vejo o uso de
using
aqui:E se:
Ou melhor ainda, pois acho que você não precisa criar um novo objeto todas as vezes.
Quanto à violação de DRY: DRY não se aplica a este nível. De fato, nenhum princípio realmente existe, exceto o da legibilidade. Tentar aplicar o DRY nesse nível é realmente apenas uma micro-otimização arquitetônica, que, como toda micro-otimização, é apenas uma troca de bicicletas e não soluciona nenhum problema, mas corre o risco de introduzir novos.
Pela minha própria experiência, sei que se você tentar reduzir a redundância de código nesse nível, criará um impacto negativo na qualidade do código, ofuscando o que era realmente claro e simples.
Edit:
Ok. Portanto, o problema não é realmente a instrução using, o problema é a dependência do objeto que você cria todas as vezes. Eu sugeriria injetar um construtor:
fonte
using (CustomTransaction transaction = new CustomTransaction())
bloco de código em nosso código para definir o escopo de uma transação. Isso não pode ser agrupado em um único objeto e, em todos os lugares em que você deseja usar uma transação, você deve escrever um bloco. Agora, e se você quiser alterar o tipo dessa transação deCustomTransaction
paraBuiltInTransaction
em mais de 500 métodos? Isso me parece uma tarefa repetida e um exemplo de violação do principal DRY.using
(neste contexto) ainda é uma "sintaxe conveniente" mais desconhecida? Por que é tão bom usar =)Não apenas o uso é de código duplicado (a propósito, ele é código duplicado e, na verdade, se compara a uma instrução try..catch..finally), mas também a toList. Eu refatoraria seu código assim:
fonte
Como não há lógica comercial de qualquer tipo aqui, exceto a última. Não é realmente SECO, na minha opinião.
O último não possui DRY no bloco using, mas acho que a cláusula where deve mudar onde quer que seja usada.
Este é um trabalho típico para geradores de código. Escreva e cubra o gerador de código e deixe-o gerar para cada tipo.
fonte
using (Entities entities = new Entities())
bloqueio. Quero dizer, essa linha de código é repetida 100 vezes e está sendo repetida cada vez mais.Como você está criando e destruindo o mesmo objeto descartável repetidamente, sua própria classe é um bom candidato para implementar o padrão IDisposable.
Isso deixa você apenas precisando do "using" ao criar uma instância da sua classe. Se você não deseja que a classe seja responsável por descartar os objetos, faça com que os métodos aceitem a dependência como argumento:
fonte
Minha parte favorita de magia incompreensível!
Wrap
existe apenas para abstrair isso ou qualquer mágica que você precisa. Não tenho certeza se recomendaria isso o tempo todo, mas é possível usá-lo. A idéia "melhor" seria usar um contêiner de DI, como StructureMap, e apenas colocar a classe Entities no contexto da solicitação, injetá-la no controlador e, então, cuidar do ciclo de vida sem a necessidade de seu controlador.fonte
Func
o suficiente.