Rozważ te metody:
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();
}
}
Korzystanie z bloku jest takie samo i zostało tutaj powtórzone 3 razy (oczywiście ponad 100 razy w prawdziwej aplikacji). Jak można zaimplementować zasadę DRY (Don't Repeat Yourself) dla using
bloku? Czy w ogóle uważa się to za naruszenie zasady DRY?
Aktualizacja: Nie mówię o tym, co zostało zaimplementowane w using
bloku. Chodzi mi o to, że using (Entities entities = new Entities())
. Ta linia jest powtarzana 100 razy lub więcej.
c#
design-patterns
dry
Saeed Neamati
źródło
źródło
Odpowiedzi:
Jednym z pomysłów byłoby owijanie go funkcją, która wymaga
Func
.Coś takiego
Wtedy twój powyższy kod staje się
Zrobiłem
Entities
też param typu, ponieważ zakładam, że masz więcej niż jeden typ, z którym to robisz. Jeśli nie, możesz go usunąć i po prostu użyć parametru type dla typu zwracanego.Szczerze mówiąc, ten rodzaj kodu wcale nie poprawia czytelności. Z mojego doświadczenia wynika, że bardziej współpracownicy Jr również mają z tym naprawdę ciężki czas.
Aktualizacja Niektóre dodatkowe odmiany pomocników, które możesz rozważyć
źródło
Entities
.IEnumerable
funkcję na wypadek, gdyby były jakieśIEnumerable
właściwości T, które dzwoniący chciał zwrócić, ale masz rację, to by to trochę wyczyściło. Być możeIEnumerable
dobrze byłoby mieć pomocnika zarówno dla singla, jak i dla wyników. To powiedziawszy, nadal myślę, że spowalnia rozpoznawanie tego, co robi kod, szczególnie dla kogoś, kto nie jest przyzwyczajony do używania wielu ogólnych i lambdas (np. Twoi współpracownicy, którzy NIE są na SO :))WithEntities
, użyjFunc<T,IEnumerable<K>>
zamiastFunc<T,K>
i nadaj „WithEntities” lepszą nazwę (np. SelectEntities). I nie sądzę, aby „jednostki” musiały być tutaj ogólnym parametrem.where T : IDisposable, new()
, tak jak jest tousing
wymaganeIDisposable
do działania.Dla mnie byłoby to tak, jakby martwić się o wielokrotne przepowiadanie tej samej kolekcji: to po prostu coś, co musisz zrobić. Jakakolwiek próba jego dalszego wyodrębnienia spowodowałaby, że kod byłby mniej czytelny.
źródło
foreach
jest w bardzo dużej kolekcji lub logika wforeach
pętli jest na przykład czasochłonna. Motto, które przyjąłem: nie ma obsesji, ale zawsze pamiętaj o swoim podejściuWygląda na to, że mylisz zasadę „Raz i tylko raz” z zasadą OSUSZANIA. Zasada DRY stanowi:
Jednak zasada „raz i tylko raz” jest nieco inna.
Zasada DRY jest zwykle stosowana w kontekście rzeczywistej logiki, nie jest zbyteczna przy użyciu instrukcji:
Źródło
źródło
Nie widzę zastosowania
using
tutaj:Co powiesz na:
Lub nawet lepiej, ponieważ nie sądzę, że musisz za każdym razem tworzyć nowy obiekt.
Jeśli chodzi o naruszenie DRY: DRY nie ma zastosowania na tym poziomie. W rzeczywistości żadna zasada tak naprawdę nie działa, z wyjątkiem zasady czytelności. Próba zastosowania DRY na tym poziomie jest tak naprawdę tylko mikrooptymalizacją architektoniczną, która podobnie jak każda mikrooptymalizacja jest po prostu zrzucaniem rowerów i nie rozwiązuje żadnych problemów, ale nawet grozi wprowadzeniem nowych.
Z własnego doświadczenia wiem, że jeśli spróbujesz zmniejszyć nadmiarowość kodu na tym poziomie, wywrzesz negatywny wpływ na jakość kodu, zaciemniając to, co było naprawdę jasne i proste.
Edycja:
Ok. Tak więc problemem nie jest tak naprawdę instrukcja using, problemem jest zależność od obiektu, który tworzysz za każdym razem. Sugerowałbym wstrzyknięcie konstruktora:
źródło
using (CustomTransaction transaction = new CustomTransaction())
bloku kodu w naszym kodzie, aby zdefiniować zakres transakcji. Tego nie da się połączyć w jeden obiekt i w każdym miejscu, w którym chcesz skorzystać z transakcji, powinieneś napisać blok. Co teraz, jeśli chcesz zmienić typ tej transakcji zCustomTransaction
naBuiltInTransaction
ponad 500 metod? Wydaje mi się, że jest to powtarzające się zadanie i przykład naruszenia zasady SUCHEGO podmiotu.using
(w tym kontekście) jest jeszcze bardziej nieznaną „wygodną składnią”? Dlaczego tak przyjemnie jest używać =)Nie tylko używanie jest duplikatem kodu (tak na marginesie, jest duplikatem kodu i faktycznie porównuje się z instrukcją try..catch..finally), ale także toList. Zmienilbym kod twojego kodu w ten sposób:
źródło
Ponieważ nie ma tutaj żadnej logiki biznesowej z wyjątkiem ostatniej. Moim zdaniem nie jest to naprawdę SUCHE.
Ten ostatni nie zawiera DRY w bloku używającym, ale myślę, że klauzula where powinna się zmienić tam, gdzie kiedykolwiek była używana.
Jest to typowe zadanie generatorów kodu. Napisz i zakryj generator kodu i pozwól mu generować dla każdego typu.
źródło
using (Entities entities = new Entities())
blok. Mam na myśli, że ten wiersz kodu jest powtarzany 100 razy i jest powtarzany coraz więcej.Ponieważ ciągle tworzysz i niszczysz ten sam obiekt jednorazowy, twoja klasa sama jest dobrym kandydatem do wdrożenia wzorca IDisposable.
To pozostawia tylko „używanie” podczas tworzenia instancji klasy. Jeśli nie chcesz, aby klasa była odpowiedzialna za usuwanie obiektów, możesz sprawić, że metody zaakceptują zależność jako argument:
źródło
Moja ulubiona odrobina niezrozumiałej magii!
Wrap
istnieje tylko po to, aby wyodrębnić tę magię lub inną potrzebną magię. Nie jestem pewien, czy poleciłbym to przez cały czas, ale można z niego korzystać. „Lepszym” pomysłem byłoby użycie kontenera DI, takiego jak StructureMap, i po prostu objęcie klasy Entities kontekstem żądania, wstrzyknięcie go do kontrolera, a następnie pozwolenie mu zająć się cyklem życia bez konieczności kontrolera.źródło
Func
wystarczająco, że powinienem.