Jestem bardzo ciekawy myśli i najlepszych praktyk branżowych dotyczących elementów statycznych lub całych klas statycznych. Czy ma to jakieś wady, czy bierze udział w jakichkolwiek anty-wzorach?
Widzę te jednostki jako „klasy / elementy użyteczności” w tym sensie, że nie wymagają ani nie wymagają tworzenia instancji klasy w celu zapewnienia funkcjonalności.
Jakie są ogólne przemyślenia i najlepsze praktyki branżowe w tym zakresie?
Zobacz poniższe przykładowe klasy i członków, aby zilustrować to, do czego się odwołuję.
// non-static class with static members
//
public class Class1
{
// ... other non-static members ...
public static string GetSomeString()
{
// do something
}
}
// static class
//
public static class Class2
{
// ... other static members ...
public static string GetSomeString()
{
// do something
}
}
Z góry dziękuję!
c#
class-design
Thomas Stringer
źródło
źródło
Odpowiedzi:
Ogólnie rzecz biorąc, unikaj statyki - szczególnie jakiegokolwiek rodzaju stanu statycznego.
Czemu?
Statyka powoduje problemy z współbieżnością. Ponieważ istnieje tylko jedna instancja, jest ona naturalnie współdzielona podczas jednoczesnego wykonywania. Te współdzielone zasoby są zmorą współbieżnego programowania i często nie muszą być dzielone.
Statyka powoduje problemy z testowaniem jednostek. Każda platforma testowania jednostkowego warta swojej soli uruchamia testy jednocześnie. Potem napotykasz na # 1. Co gorsza, komplikujesz swoje testy wszystkimi rzeczami związanymi z konfiguracją / porzuceniem oraz zhakowaniem, w które wpadniesz, próbując „udostępnić” kod instalacyjny.
Jest też wiele małych rzeczy. Statyka jest zwykle nieelastyczna. Nie możesz ich interfejsować, nie możesz ich przesłonić, nie możesz kontrolować czasu ich budowy, nie możesz ich dobrze używać w ogólnych. Naprawdę nie można ich wersji.
Z pewnością istnieją zastosowania statyki: wartości stałe działają świetnie. Czyste metody, które nie pasują do jednej klasy, mogą tu świetnie działać.
Ale ogólnie ich unikaj.
źródło
volatile
. Po prostu nie ma zapewnień z modelu pamięci bez lotnych danych, więc zmiana zmiennej w jednym wątku może nie odzwierciedlać natychmiast lub wcale.Jeśli funkcja jest „czysta”, nie widzę problemów. Funkcja czysta działa tylko w parametrach wejściowych i na tej podstawie zapewnia wynik. Nie zależy od żadnego globalnego stanu ani kontekstu zewnętrznego.
Jeśli spojrzę na twój własny przykład kodu:
Ta funkcja nie przyjmuje żadnych parametrów. Zatem prawdopodobnie nie jest czysty (jedyną czystą implementacją tej funkcji byłoby zwrócenie stałej). Zakładam, że ten przykład nie jest reprezentatywny dla twojego rzeczywistego problemu, ja tylko wskazuję, że prawdopodobnie nie jest to czysta funkcja.
Weźmy inny przykład:
Nie ma nic złego w tym, że ta funkcja jest statyczna. Możemy nawet przekształcić to w funkcję rozszerzenia, dzięki czemu kod klienta będzie jeszcze bardziej czytelny. Funkcje rozszerzeń są w zasadzie tylko szczególnym rodzajem funkcji statycznych.
Telastyn poprawnie wspomina o współbieżności jako potencjalnym problemie z elementami statycznymi. Ponieważ jednak ta funkcja nie korzysta ze stanu współdzielonego, nie występują tutaj problemy z współbieżnością. Tysiąc wątków może wywoływać tę funkcję jednocześnie bez żadnych problemów z współbieżnością.
W środowisku .NET metody rozszerzenia istnieją już od dłuższego czasu. LINQ zawiera wiele funkcji rozszerzających (np. Enumerable.Where () , Enumerable.First () , Enumerable.Single () itp.). Nie uważamy ich za złe, prawda?
Testowanie jednostkowe może często przynieść korzyści, gdy kod wykorzystuje wymienne abstrakcje, umożliwiając testowi jednostkowemu zastąpienie kodu systemowego podwójnym testem. Funkcje statyczne zabraniają tej elastyczności, ale jest to szczególnie ważne na granicach warstwy architektonicznej, gdzie chcemy na przykład zastąpić rzeczywistą warstwę dostępu do danych fałszywą warstwą dostępu do danych.
Jednak pisząc test dla obiektu, który zachowuje się inaczej, w zależności od tego, czy jakaś liczba jest nieparzysta, czy parzysta, tak naprawdę nie musimy być w stanie zastąpić
IsOdd()
funkcji alternatywną implementacją. Podobnie nie widzę, kiedy musimy zapewnić innąEnumerable.Where()
implementację do celów testowania.Sprawdźmy więc czytelność kodu klienta dla tej funkcji:
Opcja a (z funkcją zadeklarowaną jako metoda rozszerzenia):
Opcja b:
Funkcja statyczna (rozszerzenie) sprawia, że pierwszy fragment kodu jest znacznie bardziej czytelny, a czytelność ma duże znaczenie, więc w razie potrzeby używaj funkcji statycznych.
źródło