Kiedyś uwielbiałem klasy użytkowe wypełnione metodami statycznymi. Dokonali wielkiej konsolidacji metod pomocniczych, które w przeciwnym razie powodowałyby piekło redundancji i konserwacji. Są bardzo łatwe w użyciu, bez tworzenia instancji, bez utylizacji, po prostu odpal i zapomnij. Myślę, że to była moja pierwsza nieświadoma próba stworzenia architektury zorientowanej na usługi - wiele usług bezstanowych, które po prostu wykonały swoją pracę i nic więcej. Jednak wraz z rozwojem systemu pojawią się smoki.
Polimorfizm
Powiedzmy, że mamy metodę UtilityClass.SomeMethod, która radośnie brzęczy. Nagle musimy nieco zmienić funkcjonalność. Większość funkcji jest taka sama, ale mimo to musimy zmienić kilka części. Gdyby nie była to metoda statyczna, moglibyśmy stworzyć klasę pochodną i zmienić zawartość metody w razie potrzeby. Ponieważ jest to metoda statyczna, nie możemy. Jasne, jeśli musimy tylko dodać funkcjonalność przed lub po starej metodzie, możemy utworzyć nową klasę i wywołać w niej starą - ale to po prostu obrzydliwe.
Problemy z interfejsem
Metod statycznych nie można definiować za pośrednictwem interfejsów z powodów logicznych. A ponieważ nie możemy przesłonić metod statycznych, klasy statyczne są bezużyteczne, gdy musimy je przekazać przez ich interfejs. To sprawia, że nie możemy używać klas statycznych jako części wzorca strategii. Możemy załatać niektóre problemy, przekazując delegatów zamiast interfejsów .
Testowanie
Zasadniczo idzie to w parze z problemami interfejsu opisanymi powyżej. Ponieważ nasza zdolność do wymiany implementacji jest bardzo ograniczona, będziemy mieć również problem z zastąpieniem kodu produkcyjnego kodem testowym. Ponownie możemy je zawinąć, ale będzie to wymagało zmiany dużych części naszego kodu, aby móc akceptować opakowania zamiast rzeczywistych obiektów.
Wspiera obiekty blob
Ponieważ metody statyczne są zwykle używane jako metody użytkowe, a metody narzędziowe zwykle mają różne cele, szybko skończymy z dużą klasą wypełnioną niespójną funkcjonalnością - najlepiej, aby każda klasa miała jeden cel w systemie . Wolałbym mieć pięć razy więcej klas, o ile ich cele są dobrze określone.
Pełzanie parametrów
Po pierwsze, ta mała urocza i niewinna metoda statyczna może przyjmować jeden parametr. Wraz ze wzrostem funkcjonalności dodawanych jest kilka nowych parametrów. Wkrótce dodawane są kolejne parametry, które są opcjonalne, więc tworzymy przeciążenia metody (lub po prostu dodajemy wartości domyślne w językach, które je obsługują). Wkrótce mamy metodę, która przyjmuje 10 parametrów. Tylko pierwsze trzy są naprawdę wymagane, parametry 4-7 są opcjonalne. Ale jeśli określono parametr 6, wymagane jest również wypełnienie 7-9 ... Gdybyśmy utworzyli klasę, której jedynym celem jest zrobienie tego, co zrobiła ta metoda statyczna, moglibyśmy rozwiązać ten problem, przyjmując wymagane parametry w konstruktor i zezwalając użytkownikowi na ustawianie wartości opcjonalnych za pomocą właściwości lub metod w celu ustawienia wielu współzależnych wartości w tym samym czasie. Ponadto, jeśli metoda urosła do takiego stopnia złożoności,
Wymaganie od konsumentów tworzenia instancji klas bez powodu
Jednym z najczęstszych argumentów jest to, po co żądać, aby konsumenci naszej klasy utworzyli instancję wywołującą tę pojedynczą metodę, nie mając później pożytku z instancji? Tworzenie instancji klasy jest bardzo tanią operacją w większości języków, więc szybkość nie jest problemem. Dodanie dodatkowej linii kodu do konsumenta to niski koszt położenia podwalin pod znacznie łatwiejsze w utrzymaniu rozwiązanie w przyszłości. I wreszcie, jeśli chcesz uniknąć tworzenia instancji, po prostu utwórz pojedynczą otokę swojej klasy, która umożliwia łatwe ponowne użycie - chociaż wymaga to, aby Twoja klasa była bezstanowa. Jeśli nie jest bezstanowy, nadal możesz tworzyć statyczne metody opakowujące, które obsługują wszystko, a jednocześnie zapewniają wszystkie korzyści na dłuższą metę. Wreszcie,
Tylko Sith postępuje absolutnie.
Oczywiście są wyjątki od mojej niechęci do metod statycznych. Prawdziwe klasy użytkowe, które nie stwarzają żadnego ryzyka rozdęcia, są doskonałymi przypadkami dla metod statycznych - na przykład System.Convert. Jeśli twój projekt jest jednorazowy i nie ma wymagań dotyczących przyszłej konserwacji, ogólna architektura naprawdę nie jest bardzo ważna - statyczna lub niestatyczna nie ma tak naprawdę znaczenia - jednak szybkość rozwoju ma znaczenie.
Normy, normy, standardy!
Korzystanie z metod instancji nie ogranicza możliwości używania metod statycznych i na odwrót. O ile istnieje uzasadnienie za różnicowaniem i jest ustandaryzowane. Nie ma nic gorszego niż przeglądanie warstwy biznesowej obejmującej różne metody implementacji.
this
, musisz zarządzać stanem globalnym itp. Więc jeśli lubisz programowanie proceduralne, zrób to. Ale pamiętaj, że tracisz wtedy wiele strukturalnych zalet OO.Wolę sposób statyczny. Ponieważ klasa nie reprezentuje obiektu, nie ma sensu tworzyć jej instancji.
Klasy, które istnieją tylko dla ich metod, powinny pozostać statyczne.
źródło
Jeśli nie ma powodu, aby utworzyć instancję klasy w celu wykonania funkcji, użyj implementacji statycznej. Po co zmuszać konsumentów tej klasy do tworzenia instancji, gdy nie jest ona potrzebna.
źródło
Jeśli nie musisz zapisywać stanu obiektu, nie ma potrzeby tworzenia go w pierwszej kolejności. Wybrałbym pojedynczą statyczną metodę, do której przekazujesz parametry.
Ostrzegałbym również przed olbrzymią klasą Utils, która ma dziesiątki niepowiązanych metod statycznych. W pośpiechu może to spowodować dezorganizację i problemy z obsługą. Lepiej jest mieć wiele klas, każda z kilkoma powiązanymi metodami.
źródło
Powiedziałbym, że format metody statycznej byłby lepszą opcją. Uczyniłbym również klasę statyczną, dzięki czemu nie musisz się martwić o przypadkowe utworzenie instancji klasy.
źródło
Naprawdę nie wiem, jaka jest tutaj sytuacja, ale spróbuję umieścić ją jako metodę w jednej z klas, do których należą arg1, arg2 lub arg3 - Jeśli możesz semantycznie powiedzieć, że jedna z tych klas będzie właścicielem metoda.
źródło
Sugerowałbym, że trudno jest odpowiedzieć na podstawie dostarczonych informacji.
Wydaje mi się, że jeśli zamierzasz mieć tylko jedną metodę i natychmiast wyrzucisz klasę, to uczyń ją statyczną klasą, która przyjmuje wszystkie parametry.
Oczywiście trudno jest dokładnie określić, dlaczego musisz utworzyć jedną klasę tylko dla tej jednej metody. Czy jest to typowa sytuacja „klasy usług użyteczności publicznej”, jak większość zakłada? A może implementujesz jakąś klasę reguł, której może być więcej w przyszłości.
Na przykład niech ta klasa jest podłączalna. Następnie chciałbyś utworzyć interfejs dla swojej jednej metody, a następnie chciałbyś, aby wszystkie parametry były przekazywane do interfejsu, a nie do konstruktora, ale nie chciałbyś, aby był statyczny.
źródło
Czy Twoja klasa może być statyczna?
Jeśli tak, to uczyniłbym to klasą „Narzędzia”, w której umieściłbym wszystkie moje klasy z jedną funkcją.
źródło
Jeśli ta metoda jest bezstanowa i nie ma potrzeby jej przekazywania, najbardziej sensowne jest zdefiniowanie jej jako statycznej. Jeśli naprawdę potrzebujesz przekazać tę metodę, możesz rozważyć użycie delegata zamiast jednego z innych proponowanych podejść.
źródło
W przypadku prostych aplikacji i
internal
pomocników użyłbym metody statycznej. W przypadku aplikacji ze składnikami podoba mi się platforma Managed Extensibility Framework . Oto fragment dokumentu, który piszę, aby opisać wzorce, które znajdziesz w moich interfejsach API.I[ServiceName]Service
interfejs.Jako wymyślony przykład:
źródło
Po prostu zrobiłbym wszystko w konstruktorze. tak:
lub
źródło
Jeszcze jedną ważną kwestią do rozważenia jest to, czy system działałby w środowisku wielowątkowym i czy byłoby bezpieczne wątkowo mieć metodę statyczną lub zmienne ...
Należy zwrócić uwagę na stan systemu.
źródło
Może uda wam się wspólnie uniknąć tej sytuacji. Spróbuj refaktoryzować, aby uzyskać
arg1.myMethod1(arg2, arg3)
. Zamień arg1 na arg2 lub arg3, jeśli ma to większy sens.Jeśli nie masz kontroli nad klasą arg1, udekoruj ją:
Rozumowanie jest takie, że w przypadku OOP dane i metody przetwarzania tych danych należą do siebie. Plus masz wszystkie zalety, o których wspomniał Mark.
źródło
Myślę, że jeśli właściwości twojej klasy lub instancji klasy nie będą używane w konstruktorach lub w twoich metodach, metody nie powinny być zaprojektowane jako wzorzec „statyczny”. metoda statyczna powinna być zawsze traktowana jako pomoc.
źródło
W zależności od tego, czy chcesz tylko coś zrobić, czy coś zrobić i zwrócić, możesz to zrobić:
źródło