Рассмотрим эти методы:
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();
}
}
Использование блока такое же и повторялось здесь 3 раза (конечно, более 100 раз в реальном приложении). Как можно реализовать принцип DRY (не повторять себя) для using
блока? Считается ли это нарушением принципа СУХОЙ вообще?
Обновление: я не говорю о том, что было реализовано внутри using
блока. То, что я на самом деле имею в виду, это using (Entities entities = new Entities())
. Эта строка повторяется 100 и более раз.
c#
design-patterns
dry
Саид Нямати
источник
источник
Ответы:
Одна идея заключалась бы в том, чтобы обернуть его функцией, которая принимает
Func
.Что-то вроде этого
Тогда ваш код выше становится
Я также сделал параметр
Entities
типа, потому что я предполагаю, что у вас есть более одного типа, с которым вы делаете это. Если это не так, вы можете удалить его и просто использовать тип param для возвращаемого типа.Честно говоря, этот код вообще не помогает читабельности. По моему опыту, все больше Jr коллеги тоже испытывают трудности с этим.
Обновление Некоторые дополнительные варианты помощников, которые вы могли бы рассмотреть
источник
Entities
.IEnumerable
исключил эту функцию на случай, если какие-либоIEnumerable
свойства T не будут возвращены вызывающим объектом, но вы правы, он немного его очистит. Возможно,IEnumerable
было бы неплохо иметь помощника и для Single, и для результатов. Тем не менее, я все еще думаю, что это замедляет распознавание того, что делает код, особенно для тех, кто не привык использовать много обобщений и лямбд (например, ваших коллег, которые НЕ работают на SO :))WithEntities
, используйтеFunc<T,IEnumerable<K>>
вместо негоFunc<T,K>
и дайте «WithEntities» более подходящее имя (например, SelectEntities). И я не думаю, что «сущности» должны быть здесь общим параметром.where T : IDisposable, new()
, как тогоusing
требуетIDisposable
работа.Для меня это все равно, что беспокоиться о том, что вы должны несколько раз просматривать одну и ту же коллекцию: это просто то, что вам нужно сделать. Любая попытка абстрагировать его дальше сделает код гораздо менее читабельным.
источник
foreach
слишком большая коллекция или логика вforeach
цикле занимает много времени, например. Девиз, который я пришел принять: не зацикливайся, но всегда помни о своем подходеПохоже, вы путаете принцип «Один раз и только один раз» с принципом СУХОЙ. Принцип СУХОЙ гласит:
Однако принцип «Один раз и только один раз» немного отличается.
Принцип СУХОГО обычно используется в контексте реальной логики, а не столько избыточен при использовании операторов:
Источник
источник
Я не вижу использования
using
здесь:Как насчет:
Или даже лучше, так как я не думаю, что вам нужно каждый раз создавать новый объект.
Что касается нарушения DRY: DRY не применяется на этом уровне. На самом деле ни один принцип на самом деле не действует, кроме принципа читабельности. Попытка применить DRY на этом уровне на самом деле является лишь архитектурной микрооптимизацией, которая, как и всякая микрооптимизация, является просто избавлением от велосипеда и не решает никаких проблем, но даже рискует внедрять новые.
Исходя из собственного опыта, я знаю, что если вы попытаетесь уменьшить избыточность кода на этом уровне, вы окажете негативное влияние на качество кода, запутывая то, что было действительно ясным и простым.
Редактировать:
ОК. Таким образом, проблема на самом деле не в использовании выражения, а в зависимости от объекта, который вы создаете каждый раз. Я бы предложил ввести конструктор:
источник
using (CustomTransaction transaction = new CustomTransaction())
блок кода в нашем коде, чтобы определить объем транзакции. Это нельзя связать в один объект, и в каждом месте, где вы хотите использовать транзакцию, вы должны написать блок. А что если вы захотите изменить тип этой транзакцииCustomTransaction
наBuiltInTransaction
более чем 500 методов? Мне кажется, что это повторяющаяся задача и пример нарушения принципа СУХОЙ.using
(в этом контексте) еще более неизвестным «удобным синтаксисом»? Почему это так приятно использовать =)Не только использование является дублирующим кодом (кстати, он является дублирующим кодом и фактически сравнивается с оператором try..catch..finally), но и списком toList. Я бы изменил ваш код следующим образом:
источник
Поскольку здесь нет никакой бизнес-логики, кроме последней. Это не очень СУХОЙ, на мой взгляд.
У последнего нет СУХОГО в блоке using, но я предполагаю, что предложение where должно измениться, где бы оно ни использовалось.
Это типичная работа для генераторов кода. Напишите и покройте генератор кода и дайте ему сгенерировать для каждого типа.
источник
using (Entities entities = new Entities())
блок. Я имею в виду, что эта строка кода повторяется 100 раз и повторяется все больше и больше.Поскольку вы создаете и уничтожаете один и тот же одноразовый объект снова и снова, ваш класс сам по себе является хорошим кандидатом для реализации шаблона IDisposable.
Это оставляет вам только необходимость использования при создании экземпляра вашего класса. Если вы не хотите, чтобы класс отвечал за удаление объектов, вы можете заставить методы принимать зависимость в качестве аргумента:
источник
Мой любимый кусочек непостижимой магии!
Wrap
существует только для того, чтобы абстрагироваться от этой магии или от того, что вам нужно Я не уверен, что рекомендовал бы это все время, но возможно использовать. «Лучшей» идеей было бы использовать DI-контейнер, такой как StructureMap, и просто поместить класс Entities в контекст запроса, внедрить его в контроллер и затем позволить ему позаботиться о жизненном цикле без необходимости в вашем контроллере.источник
Func
достаточно, я должен.