Czy metody, które nie zależą od pól instancji, są statyczne?

19

Ostatnio zacząłem programować w Groovy dla środowiska testowego integracji, dla projektu Java. Używam Intellij IDEA z wtyczką Groovy i jestem zaskoczony, widząc ostrzeżenie dla wszystkich metod, które są niestatyczne i nie zależą od pól instancji. Jednak w Javie nie stanowi to problemu (przynajmniej z punktu widzenia IDE).

Czy wszystkie metody, które nie zależą od pól instancji, powinny zostać przekształcone w funkcje statyczne? Jeśli prawda, czy jest to specyficzne dla Groovy, czy ogólnie jest dostępne dla OOP? I dlaczego?

m3th0dman
źródło
Czy te metody wywołują inne metody instancji? A może dosłownie nie mają nic wspólnego z przedmiotem tej klasy? Czy możesz podać przykład?
Ray Toal

Odpowiedzi:

26

Pamiętaj, że IDEA ma również tę inspekcję w Javie, nazywa się to Metoda może być „statyczna” ,

Ta inspekcja zgłasza wszelkie metody, które można bezpiecznie unieruchomić. Metoda może być statyczna, jeśli nie odwołuje się do żadnych metod niestatycznych i pól niestatycznych swojej klasy i nie jest zastępowana w podklasie ...

Rzecz w tym, że w przypadku kodu Java ta kontrola jest domyślnie wyłączona (programiści mogą ją włączyć według własnego uznania). Powodem tego jest najprawdopodobniej, że ważność / przydatność takiej inspekcji mogłaby zostać zakwestionowana na podstawie kilku dość wiarygodnych źródeł.

Na początek oficjalny samouczek Java jest raczej ograniczony, kiedy metody powinny być statyczne:

Częstym zastosowaniem metod statycznych jest dostęp do pól statycznych.

Biorąc pod uwagę powyższe, można argumentować, że włączenie domyślnie wspomnianej kontroli nie jest zgodne z zalecanym użyciem modyfikatora statycznego w Javie.

Poza tym istnieje kilka innych źródeł, które sięgają tak daleko, że sugerują rozsądne podejście do korzystania z pomysłów leżących u podstaw tej kontroli, a nawet zniechęcają ją.

Zobacz na przykład artykuł Java World - Mr. Happy Object uczy metod statycznych :

Każda metoda, która jest niezależna od stanu instancji, może zostać zadeklarowana jako statyczna.

Pamiętaj, że mówię „kandydat do bycia zadeklarowanym jako statyczny”. Nawet w poprzednim przykładzie nic nie zmusza cię do zadeklarowania instances()jako statycznego. Zadeklarowanie go jako statycznego sprawia, że ​​wygodniej jest wywoływać, ponieważ nie potrzebujesz instancji, aby wywołać metodę Czasami będziesz mieć metody, które wydają się nie polegać na stanie instancji. Być może nie chcesz, aby te metody były statyczne. W rzeczywistości prawdopodobnie będziesz chciał zadeklarować je jako statyczne, jeśli potrzebujesz do nich dostępu bez instancji.

Co więcej, nawet jeśli możesz zadeklarować taką metodę jako statyczną, możesz tego nie chcieć z powodu problemów z dziedziczeniem, które wtrąca się w twój projekt. Spójrz na „Efektywne projektowanie obiektowe”, aby zobaczyć niektóre z problemów, z którymi się spotkasz ...

Artykuł na blogu testowym Google mówi nawet, że metody statyczne to śmierć na testowalność :

Zróbmy ćwiczenie mentalne. Załóżmy, że twoja aplikacja ma tylko statyczne metody. (Tak, taki kod można napisać, nazywa się to programowaniem proceduralnym.) Teraz wyobraź sobie graf wywołania tej aplikacji. Jeśli spróbujesz wykonać metodę liścia, nie będziesz mieć problemu z ustawieniem jej stanu i potwierdzeniem wszystkich przypadków narożnych. Powodem jest to, że metoda liścia nie wykonuje dalszych wywołań. W miarę oddalania się od liści i zbliżania się do main()metody rootowania coraz trudniej będzie ustawić stan w teście i trudniej będzie stwierdzić. Wiele rzeczy stanie się niemożliwych do stwierdzenia. Twoje testy będą się stopniowo powiększać. Po dotarciu domain()metoda, w której nie masz już testu jednostkowego (ponieważ twoją jednostką jest cała aplikacja) masz teraz test scenariuszowy. Wyobraź sobie, że aplikacja, którą próbujesz przetestować, to edytor tekstu. Nie można wiele stwierdzić na podstawie głównej metody ...

Czasami metody statyczne są fabryką dla innych obiektów. To dodatkowo nasila problem z testowaniem. W testach polegamy na tym, że możemy różnie łączyć obiekty, zastępując ważne zależności próbnymi. Po newwywołaniu operatora nie możemy zastąpić metody podklasą. Osoba wywołująca taką statyczną fabrykę jest trwale związana z konkretnymi klasami, które wytworzyła metoda statycznej fabryki. Innymi słowy, uszkodzenie metody statycznej znacznie wykracza poza samą metodę statyczną. Włączenie okablowania wykresów obiektowych i kodu konstrukcyjnego do metody statycznej jest wyjątkowo złe, ponieważ okablowanie wykresów obiektowych to sposób, w jaki izolujemy rzeczy do testowania ...


Widzisz, biorąc pod uwagę powyższe, wydaje się naturalne, że wspomniana inspekcja jest domyślnie wyłączona w Javie.

Deweloperzy IDE miałoby naprawdę trudno wyjaśnić, dlaczego uważają, że tak ważne jest, aby ustawić go na domyślnie przeciwko powszechnie uznanych zaleceń i najlepszych praktyk.

W przypadku Groovy sprawy wyglądają zupełnie inaczej. Żaden z wyżej wymienionych argumentów nie ma zastosowania, szczególnie ten dotyczący testowalności, jak wyjaśniono np. W Mocking Static Methods w artykule Groovy w Javalobby:

Jeśli testowana klasa Groovy wywołuje metodę statyczną w innej klasie Groovy, możesz użyć ExpandoMetaClass, która umożliwia dynamiczne dodawanie metod, konstruktorów, właściwości i metod statycznych ...

Ta różnica jest prawdopodobna, dlaczego domyślne ustawienie wspomnianej kontroli jest odwrotne w Groovy. Podczas gdy w Javie domyślne „włączone” byłoby źródłem zamieszania wśród użytkowników, w Groovy przeciwne ustawienie mogłoby pomylić użytkowników IDE.

„Hej, metoda nie wykorzystuje pól instancji, dlaczego mnie przed tym nie ostrzegłeś?” Odpowiedź na to pytanie byłaby łatwa w przypadku Javy (jak wyjaśniono powyżej), ale w przypadku Groovy nie ma żadnego przekonującego wyjaśnienia.

komar
źródło
Nawiasem mówiąc, ReSharper (stworzony przez JetBrains dla C # / Visual Studio) sugeruje to samo
Konrad Morawski
6
Istnieje istotna różnica między metodami statycznymi z efektami ubocznymi i bez nich. Wyciąg Google naprawdę odnosi się do tego pierwszego.
assylias
@assylias Tak, ale omawia również, w jaki sposób metody fabryczne mogą utrudnić testowanie (ponieważ ściśle wiąże zależności w aplikacji). Korzystanie ze struktury wstrzykiwania zależności jest jednym z najlepszych obejść tego problemu, a także rozwiązuje wiele innych problemów.
Per Lundberg
5

Trudno sobie wyobrazić, aby miałoby to jakikolwiek zauważalny wpływ na wydajność. Jedyną korzyścią, jaką widzę, gdy je robię, staticjest to, że zapewnia wizualne wskazanie, że nie ma to wpływu na stan instancji. Innymi słowy, mówi osobie czytającej kod źródłowy coś ... „interesującego” o tej metodzie, tylko dlatego, że tam jest. Prawdziwe pytanie brzmi: czy to wyjaśnia, czy dezorientuje? „Dlaczego ta metoda jest statyczna? Czy jest to metoda fabryczna? Czy potrzebna jest możliwość wywoływania jej bez instancji obiektu?”

Ponadto niektórzy ludzie nie lubią metod statycznych, ponieważ twierdzą, że nie można ich wyśmiewać, a zatem nie można ich przetestować lub coś w tym stylu. Oczywiście, jeśli ustawisz go na statyczny z któregokolwiek ze zwykłych powodów, takich jak na przykład dostarczenie metody fabrycznej, to jestem za tym wszystkim. Nie jestem do końca pewien, czy uczynienie metod statycznymi tylko dlatego, że nie dotykają stanu instancji, jest mandatem.

Robert Harvey
źródło
5
Weź pod uwagę, że (w Javie) nie można zastąpić metody statycznej. Chociaż nie jest to często problem, oznacza to, że niektóre podklasy nie mogą później zmienić tej implementacji. Nie oznacza to, że metoda statyczna nie jest właściwą odpowiedzią, ale raczej częścią rozważań projektowych.
2
@ user40980 warto wziąć pod uwagę, prawda, ale warto również wziąć pod uwagę, że dziedziczenie może być niezdarnym narzędziem, które jest często niewłaściwie używane, a kilka wybitnych postaci twierdzi, że wszystkie klasy powinny być finalzaprojektowane lub specjalnie zaprojektowane z myślą o dziedziczeniu.
sara,
3

Myślę, że jest umożliwienie ewentualnego refaktoryzacji zostać zauważony .

Gdy metoda stanie się statyczna, jasne jest , że można ją przenieść z klasy, powiedzmy do klasy jedności.

Łatwo jest również przekształcić go w metodę instancji jednego z jego parametrów, często tam powinien być kod.

Ian
źródło
-1

Zauważ, że możesz mieć klasy bezstanowe, które implementują jakiś interfejs (np. java.lang.Runnable- nie możesz ustawić ich metod na statyczne. Niektóre wzorce (np. Strategia) mogą również tworzyć bezstanowe obiekty, które mogą mieć nawet kilka metod.

Statyka jest pierwszą kuzynką singletonów. Naprawdę ciężko będzie przejść ze statyki do niestatyki w późniejszym momencie - więc kiedy będziesz musiał dodać stan, będziesz miał ochotę zacząć wprowadzać zmienne statyczne.

Eugene
źródło
Jak to odpowiada na zadane pytanie?
komar
1
dlaczego trudno jest przejść z żadnego stanu do jakiegoś stanu? Powiedziałbym, że jest na odwrót. łatwiej jest zanieczyścić coś czystego niż oczyścić coś zanieczyszczonego.
sara,