Mam metodę, która przyjmuje 30 parametrów. Wziąłem parametry i umieściłem je w jednej klasie, tak że mogłem po prostu przekazać jeden parametr (klasę) do metody. Czy w przypadku refaktoryzacji jest całkowicie w porządku, aby przekazać obiekt, który zawiera wszystkie parametry, nawet jeśli to wszystko, co zawiera.
c#
oop
refactoring
Xaisoft
źródło
źródło
Odpowiedzi:
To jest świetny pomysł. Jest to zwykle sposób, w jaki kontrakty danych są wykonywane na przykład w programie WCF.
Jedną z zalet tego modelu jest to, że jeśli dodasz nowy parametr, konsument klasy nie musi zmieniać tylko w celu dodania parametru.
Jak wspomina David Heffernan, może pomóc samodzielnie udokumentować kod:
FrobRequest frobRequest = new FrobRequest { FrobTarget = "Joe", Url = new Uri("http://example.com"), Count = 42, }; FrobResult frobResult = Frob(frobRequest);
źródło
Podczas gdy inne odpowiedzi tutaj poprawnie wskazują, że przekazanie wystąpienia klasy jest lepsze niż przekazanie 30 parametrów, należy pamiętać, że duża liczba parametrów może być symptomem podstawowego problemu.
Np. Wiele razy metody statyczne zwiększają liczbę parametrów, ponieważ powinny one być przez cały czas metodami instancji, a Ty przekazujesz wiele informacji, które można by łatwiej utrzymać w instancji tej klasy.
Alternatywnie poszukaj sposobów grupowania parametrów w obiekty o wyższym poziomie abstrakcji. Zrzucenie zestawu niepowiązanych parametrów do jednej klasy to rozwiązanie IMO ostatniej szansy.
Zobacz Ile parametrów to za dużo? po więcej pomysłów na ten temat.
źródło
To dobry początek. Ale teraz, gdy masz już tę nową klasę, rozważ obrócenie kodu na lewą stronę. Przenieś metodę, która przyjmuje tę klasę jako parametr do nowej klasy (oczywiście przekazując instancję oryginalnej klasy jako parametr). Teraz masz dużą metodę, samą w klasie, i łatwiej będzie ją podzielić na mniejsze, łatwiejsze w zarządzaniu i testowalne metody. Niektóre z tych metod mogą powrócić do oryginalnej klasy, ale spora część prawdopodobnie pozostanie w nowej klasie. Przeszedłeś dalej niż wprowadzenie obiektu parametru, aby zamienić metodę na obiekt metody .
Posiadanie metody z trzydziestoma parametrami to dość silny znak, że metoda jest zbyt długa i zbyt skomplikowana. Zbyt trudne do debugowania, zbyt trudne do przetestowania. Powinieneś więc coś z tym zrobić, a Wprowadzenie obiektu parametru to dobre miejsce na początek.
źródło
Chociaż refaktoryzacja do obiektu parametru nie jest sama w sobie złym pomysłem, nie powinna być używana do ukrycia problemu, że klasa, która potrzebuje 30 elementów danych dostarczonych z innego miejsca, może nadal pachnieć kodem. Refaktoryzację obiektu parametru wprowadzenia należy prawdopodobnie traktować raczej jako krok na drodze w szerszym procesie refaktoryzacji niż jako koniec tej procedury.
Jedną z obaw, których tak naprawdę nie rozwiązuje, jest Feature Envy. Czy fakt, że klasa, do której przekazywany jest obiekt parametrów, jest tak zainteresowana danymi innej klasy, nie wskazuje na to, że może metody działające na tych danych powinny zostać przeniesione do miejsca, w którym te dane się znajdują? Naprawdę lepiej jest zidentyfikować klastry metod i danych, które należą do siebie i pogrupować je w klasy, zwiększając w ten sposób hermetyzację i uelastyczniając kod.
Po kilku iteracjach rozdzielania zachowania i danych, na których działa, na oddzielne jednostki, powinieneś zauważyć, że nie masz już żadnych klas z ogromną liczbą zależności, co zawsze jest lepszym wynikiem końcowym, ponieważ uczyni twój kod bardziej elastycznym.
źródło
To doskonały pomysł i bardzo powszechne rozwiązanie problemu. Metody z więcej niż 2 lub 3 parametrami stają się wykładniczo coraz trudniejsze do zrozumienia.
Zamknięcie tego wszystkiego w jednej klasie sprawia, że kod jest znacznie bardziej przejrzysty. Ponieważ Twoje właściwości mają nazwy, możesz napisać samodokumentujący kod w następujący sposób:
params.height = 42; params.width = 666; obj.doSomething(params);
Oczywiście, gdy masz wiele parametrów, alternatywa oparta na identyfikacji pozycyjnej jest po prostu okropna.
Kolejną korzyścią jest to, że dodawanie dodatkowych parametrów do kontraktu interfejsu można wykonać bez wymuszania zmian we wszystkich lokalizacjach połączeń. Jednak nie zawsze jest to tak trywialne, jak się wydaje. Jeśli różne miejsca wywołań wymagają różnych wartości nowego parametru, trudniej jest je znaleźć niż w przypadku podejścia opartego na parametrach. W podejściu opartym na parametrach dodanie nowego parametru wymusza zmianę w każdym miejscu wywołania w celu dostarczenia nowego parametru i można pozwolić kompilatorowi na znalezienie ich wszystkich.
źródło
Martin Fowler w swojej książce Refaktoryzacja nazywa ten obiekt „ Wprowadzanie parametrów” . Mając to na uwadze, niewielu nazwałoby to złym pomysłem.
źródło
30 parametrów to bałagan. Myślę, że o wiele ładniej jest mieć klasę z właściwościami. Można nawet utworzyć wiele „klas parametrów” dla grup parametrów pasujących do tej samej kategorii.
źródło
Możesz również rozważyć użycie struktury zamiast klasy.
Ale to, co próbujesz zrobić, jest bardzo powszechne i świetny pomysł!
źródło
Może być rozsądne użycie klasy zwykłych starych danych, niezależnie od tego, czy dokonujesz refaktoryzacji, czy nie. Ciekawi mnie, dlaczego pomyślałeś, że tak nie jest.
źródło
Może opcjonalne i nazwane parametry C # 4.0 będą dobrą alternatywą?
W każdym razie metoda, którą opisujesz, może być również dobra do abstrakcji zachowania programów. Na przykład możesz mieć jedną standardową
SaveImage(ImageSaveParameters saveParams)
funkcję w interfejsie, któraImageSaveParameters
również jest interfejsem i może mieć dodatkowe parametry w zależności od formatu obrazu. Na przykładJpegSaveParameters
maQuality
-właściwość, podczas gdyPngSaveParameters
maBitDepth
-właściwość.W ten sposób robi to okno dialogowe zapisywania w Paint.NET, więc jest to bardzo realny przykład.
źródło
Jak wspomniano wcześniej: jest to właściwy krok, ale weź pod uwagę również następujące kwestie:
źródło
Tyle świetnych odpowiedzi. Chciałbym dodać moje dwa centy.
Obiekt parametru to dobry początek. Ale można zrobić więcej. Rozważ następujące (przykłady w języku Ruby):
/ 1 / Zamiast po prostu grupować wszystkie parametry, sprawdź, czy może istnieć sensowne grupowanie parametrów. Możesz potrzebować więcej niż jednego obiektu parametrów.
def display_line(startPoint, endPoint, option1, option2)
może stać się
def display_line(line, display_options)
/ 2 / Obiekt parametru może mieć mniejszą liczbę właściwości niż pierwotna liczba parametrów.
może stać się
def double_click?(first_click_info, second_click_info) # MouseClickInfo being the parameter object type # having cursor_location and control_at_click as properties
Takie zastosowania pomogą Ci odkryć możliwości dodania znaczącego zachowania do tych obiektów parametrów. Przekonasz się, że wcześniej otrząsną się z początkowego zapachu klasy danych, aby zapewnić Ci wygodę. : -)
źródło