2008-10-14 34 views
27

Pracuję nad projektem w języku C#. Poprzedni programista nie znał programowania obiektowego, więc większość kodu znajduje się w ogromnych plikach (mówimy o 4-5000 liniach) rozłożonych na dziesiątki, a czasem setki metod, ale tylko na jedną klasę. Refaktoryzacja takiego projektu jest ogromnym przedsięwzięciem, więc na razie na wpół nauczyłem się z nim żyć.Wydajność korzystania z metod statycznych a tworzenie instancji klasy zawierającej metody

Ilekroć w jednym z plików kodu stosowana jest metoda, tworzona jest instancja klasy, a następnie wywoływana jest metoda w instancji obiektu.

Zastanawiam się, czy istnieją jakieś zauważalne kary za wydajność w robieniu tego w ten sposób? Czy powinienem uczynić wszystkie metody statycznymi "na teraz" i, co najważniejsze, czy aplikacja będzie w jakikolwiek sposób z nich korzystać?

+0

myślę, że to powinno być przeniesione do CS.SE –

Odpowiedz

24

Od here, wywołanie statyczne jest 4 do 5 razy szybsze niż konstruowanie instancji za każdym razem, gdy wywoływana jest metoda instancji. Jednak wciąż mówimy tylko o dziesiątkach nanosekund na każde połączenie, więc prawdopodobnie nie zauważysz żadnych korzyści, chyba że masz naprawdę napięte pętle wywołujące metodę miliony razy, a ty możesz uzyskać tę samą korzyść przez skonstruowanie jednego wystąpienia na zewnątrz tę pętlę i ponowne jej wykorzystanie.

Ponieważ musisz zmienić wszystkie strony z ogłoszeniami, aby skorzystać z nowej metody statycznej, prawdopodobnie lepiej poświęcić swój czas na stopniową refaktoryzację.

+0

Fantastyczny artykuł. Właśnie zacząłem to robić, ponieważ interesowałem się tym, co jest szybsze. "While object.read" lub For-Loop i IF. I ten artykuł jest po prostu idealny po moich osobistych badaniach. Bardzo dobrze. Teraz mam bardzo duży obiekt, do którego można uzyskać dostęp z wielu miejsc i zastanawiałem się, czy warto przepuścić tę metodę metodą do miejsca, do którego musi się udać, lub po prostu utworzyć globalną klasę zmiennych i uzyskać do niej dostęp. Trudno przetestować, co będzie szybciej ...? :( –

2

Wydaje mi się głupie, aby utworzyć obiekt TYLKO dlatego, że można wywołać metodę, która pozornie nie ma skutków ubocznych dla obiektu (na podstawie opisu zakładam, że to). Wydaje mi się, że lepszym kompromisem byłoby posiadanie kilku globalnych obiektów i po prostu ich używać. W ten sposób możesz umieścić zmienne, które normalnie byłyby globalne, w odpowiednich klasach, aby miały nieco mniejszy zakres.

Stamtąd można powoli przesuwać zakres tych obiektów, aby były mniejsze i mniejsze, aż do uzyskania przyzwoitego projektu OOP.

Z drugiej strony podejście, które prawdopodobnie użyje I jest inne;).

Osobiście prawdopodobnie skoncentruję się na strukturach i funkcjach, które na nich działają, i staram się je przekształcić w klasy z członkami po trochu.

Co do aspektu wydajnościowego, metody statyczne powinny być nieco szybsze (ale nie za duże), ponieważ nie wymagają konstruowania, przekazywania i dekonstrukcji obiektu.

3

Wydaje mi się, że częściowo odpowiedziałeś na to pytanie w sposób, w jaki go poprosiłeś: czy w kodzie, który posiadasz, są jakieś kary za wykonanie zauważalne?

Jeśli kary nie są zauważalne, nie musisz wcale robić niczego. (Choć nie trzeba dodawać, że baza kodowa odniosłaby dramatyczne korzyści ze stopniowego refaktoryzatora do godnego szacunku modelu OO).

Domyślam się, że mówię, że problem z wydajnością jest problemem tylko wtedy, gdy zauważysz, że to problem.

7

To zależy od tego, co jeszcze zawiera ten obiekt - jeśli "obiekt" to tylko garść funkcji, to prawdopodobnie nie jest to koniec świata. Ale jeśli obiekt zawiera grupę innych obiektów, wtedy tworzenie instancji wywoła wszystkie ich konstruktory (i destruktory, kiedy zostaną usunięte) i możesz dostać fragmentację pamięci i tak dalej.

To powiedziawszy, nie wydaje się, że wydajność jest obecnie największym problemem.

9

Mam do czynienia z podobnym problemem, gdzie pracuję. Programista przede mną stworzył 1 klasę kontrolera, w której wszystkie funkcje BLL zostały zrzucone.

Teraz przeprojektowujemy system i stworzyliśmy wiele klas kontrolerów w zależności od tego, co mają kontrolować, np.

UserController, GeographyController, ShoppingController ...

Wewnątrz każdej klasie kontrolera mają metody statyczne, które wykonywanie połączeń do pamięci podręcznej lub DAL przy użyciu Singleton.

To dało nam 2 główne zalety. Jest nieco szybszy (około 2-3 razy szybciej, ale tutaj mówimy o nanosekundach; P). Drugą jest to, że kod jest znacznie czystsze

tj

ShoppingController.ListPaymentMethods() 

zamiast

new ShoppingController().ListPaymentMethods() 

myślę, że to ma sens, aby użyć metody statyczne lub klasy, jeśli klasa nie utrzymują żadnego państwa .

5

Musisz określić cele przepisywania. Jeśli chcesz mieć ładny testowalny, rozszerzalny kod OO możliwy do utrzymania, możesz spróbować użyć obiektów i ich metod instancji. Po tym wszystkim chodzi o programowanie zorientowane obiektowo, o którym tutaj mowa, a nie o programowanie klasowe.

Bardzo proste jest sfałszowanie i/lub symulowanie obiektów podczas definiowania klas implementujących interfejsy i wykonywania metod instancji. Dzięki temu dokładne testy jednostkowe są szybkie i skuteczne.

Ponadto, jeśli masz przestrzegać dobrych zasad OO (patrz SOLID w http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29) i/lub używać wzorców projektowych, na pewno będziesz wykonywał wiele aplikacji opartych na instancjach, opartych na interfejsach i nie używając wielu metod statycznych.

Co do tej sugestii:

Wydaje się głupie mi się stworzyć obiekt tylko tak można wywołać metodę, która pozornie nie ma skutków ubocznych na obiekcie (z opisem Zakładam).

widzę to dużo w sklepach dot netto i dla mnie to jest niezgodny enkapsulacji, kluczową OO koncepcji. Nie powinienem być w stanie stwierdzić, czy dana metoda ma skutki uboczne, niezależnie od tego, czy metoda jest statyczna. Oprócz łamania enkapsulacji oznacza to, że będziesz musiał zmieniać metody ze statycznej na instancję, jeśli/kiedy zmodyfikujesz je tak, by wywoływały efekty uboczne. Sugeruję, abyś przeczytał na temat zasady Open/Closed dla tego i zobacz, jak sugerowane podejście, przytoczone powyżej, działa z myślą o tym.

Pamiętaj, że stary kasztan, "przedwczesna optymalizacja jest źródłem wszelkiego zła". Myślę, że w tym przypadku oznacza to, że nie przeskakuje przez obręcze za pomocą niewłaściwych technik (tj. Programowanie w klasie), dopóki nie będziesz mieć problemu z wydajnością. Nawet wtedy debuguj problem i szukaj najbardziej odpowiedniego.

2

Metody statyczne są dużo szybsze i zużywają o wiele mniej pamięci. Istnieje takie błędne przekonanie, że jest tylko trochę szybszy. Jest trochę szybszy, o ile nie włożysz go w pętle. BTW, niektóre pętle wyglądają na małe, ale tak naprawdę nie są, ponieważ wywołanie metody zawierające pętlę jest również inną pętlą. Możesz odróżnić kod, który wykonuje funkcje renderowania. Dużo mniej pamięci jest niestety prawdziwe w wielu przypadkach. Instancja umożliwia łatwe udostępnianie informacji za pomocą metod siostrzanych. Statyczna metoda poprosi o informację, kiedy jej potrzebuje.

Ale jak w prowadzeniu samochodów, prędkość przynosi odpowiedzialność. Metody statyczne mają zwykle więcej parametrów niż ich odpowiednik. Ponieważ instancja zajmie buforowanie współdzielonych zmiennych, metody instancji będą wyglądać ładniej.

ShapeUtils.DrawCircle(stroke, pen, origin, radius); 

ShapeUtils.DrawSquare(stroke, pen, x, y, width, length); 

VS

ShapeUtils utils = new ShapeUtils(stroke,pen); 

util.DrawCircle(origin,radius); 

util.DrawSquare(x,y,width,length); 

W tym przypadku, gdy zmienne instancji są używane przez wszystkich metod większość czasu, metody instancji są bardzo warto. Instancje NIE SĄ O PAŃSTWIE, chodzi o UDOSTĘPNIANIE, chociaż WSPÓLNY STAN jest naturalną formą UDZIAŁU, NIE JEST TAKIE SAME. Ogólna zasada jest taka: jeśli metoda jest ściśle powiązana z innymi metodami - kochają się nawzajem tak bardzo, że gdy jeden jest nazywany, drugi też musi być nazywany i prawdopodobnie dzieli on tę samą filiżankę wody - -, powinna być wykonana instancja. Tłumaczenie metod statycznych na metody instancji nie jest takie trudne. Musisz tylko wziąć wspólne parametry i umieścić je jako zmienne instancji. Odwrotnie jest trudniej.

Lub możesz utworzyć klasę proxy, która będzie mostem statycznych metod. Choć teoretycznie może się to wydawać mniej efektywne, praktyka opowiada inną historię. Dzieje się tak dlatego, że gdy chcesz raz wywołać DrawSquare (lub w pętli), przejdziesz od razu do metody statycznej. Ale kiedy będziesz go używać w kółko wraz z DrawCircle, użyjesz proxy instancji. Przykładem są klasy System.IO FileInfo (instancja) a plik (statyczne).

Metody statyczne można przetestować. W rzeczywistości nawet więcej testowalne niż instancja raz. Metoda GetSum (x, y) byłaby bardzo testowalna nie tylko testem jednostkowym, ale testem obciążeniowym, zintegrowanym testem i testem użycia. Metody instancji są dobre dla testów jednostek, ale straszne dla każdego innego testu (co jest ważniejsze niż testy jednostek BTW), dlatego mamy tak wiele błędów w tych dniach. Rzeczą, która sprawia, że ​​WSZYSTKIE metody są niepoprawne, są parametry, które nie mają sensu (np. Sender, EventArgs e) lub stan globalny, taki jak DateTime.Now. W rzeczywistości statyczne metody są tak dobre w testowalności, że widzisz mniej błędów w kodzie C nowej dystrybucji Linuksa niż przeciętny programista OO (jest on pełen s *** Wiem).