Widziałem ten wątek
Jeśli klasa „Utilities” jest zła, gdzie mam umieścić swój ogólny kod?
i pomyślał, dlaczego klasy użytkowe są złe?
Powiedzmy, że mam model domeny, który obejmuje dziesiątki klas. Muszę mieć możliwość obsługi instancji xml-ify. Czy utworzyć metodę toXml na rodzicu? Czy mogę utworzyć klasę pomocniczą MyDomainXmlUtility.toXml? Jest to przypadek, w którym potrzeba biznesowa obejmuje cały model domeny - czy naprawdę należy do metody instancji? A co, jeśli istnieje kilka metod pomocniczych dotyczących funkcjonalności XML aplikacji?
design-patterns
software-design
hvgotcodes
źródło
źródło
Odpowiedzi:
Klasy użytkowe nie są dokładnie złe, ale mogą naruszać zasady, które składają się na dobry projekt zorientowany obiektowo. W dobrym projekcie obiektowym większość klas powinna reprezentować jedną rzecz oraz wszystkie jej atrybuty i operacje. Jeśli operujesz na jakiejś rzeczy, ta metoda powinna prawdopodobnie należeć do tej rzeczy.
Czasami jednak można użyć klas narzędziowych do zgrupowania kilku metod razem - przykładem jest
java.util.Collections
klasa udostępniająca szereg narzędzi, których można użyć w dowolnej kolekcji Java. Nie są one specyficzne dla jednego konkretnego typu kolekcji, ale zamiast tego implementują algorytmy, które mogą być używane w dowolnej kolekcji.Naprawdę, to, co musisz zrobić, to przemyśleć swój projekt i określić, gdzie najlepiej jest umieścić metody. Zwykle jest to operacje wewnątrz klasy. Jednak czasami jest to rzeczywiście klasa użytkowa. Jednak gdy używasz klasy narzędziowej, nie wrzucaj do niej tylko losowych metod, zamiast tego organizuj metody według przeznaczenia i funkcjonalności.
źródło
Myślę, że ogólny konsensus jest taki, że klasy użytkowe nie są złe same w sobie . Musisz tylko rozsądnie ich używać:
Zaprojektuj statyczne metody narzędziowe tak, aby były ogólne i wielokrotnego użytku. Upewnij się, że są bezpaństwowcami; tj. brak zmiennych statycznych.
Jeśli masz wiele metod narzędziowych, podziel je na klasy w sposób, który ułatwi programistom ich znalezienie.
Nie używaj klas narzędzi, w przypadku których lepszym rozwiązaniem byłyby metody statyczne lub instancyjne w klasie domeny. Na przykład zastanów się, czy lepszym rozwiązaniem byłyby metody w abstrakcyjnej klasie bazowej lub instancji klasy pomocniczej.
W przypadku języka Java 8 i nowszych „metody domyślne” w interfejsie mogą być lepszą opcją niż klasy narzędziowe. (Zobacz na przykład Interfejs z metodami domyślnymi a Klasa abstrakcyjna w języku Java 8 ).
Innym sposobem spojrzenia na to pytanie jest zauważenie, że w zacytowanym pytaniu „Jeśli klasy użyteczności są„ złe ”” jest argumentem słomnika. Tak jak ja pytam:
W powyższym pytaniu nie mówię właściwie, że świnie potrafią latać ... ani że zgadzam się z tezą, że potrafią latać.
Typowe stwierdzenia „xyz to zło” to narzędzia retoryczne, które mają skłonić cię do myślenia, przedstawiając skrajny punkt widzenia. Rzadko (jeśli w ogóle) są pomyślane jako stwierdzenia dosłownych faktów.
źródło
Klasy narzędziowe są problematyczne, ponieważ nie grupują obowiązków z danymi, które je obsługują.
Są jednak niezwykle przydatne i cały czas buduję je jako konstrukcje stałe lub jako odskocznię podczas dokładniejszego refaktora.
Z punktu widzenia czystego kodu klasy użytkowe naruszają pojedynczą odpowiedzialność i zasadę otwartego zamknięcia. Mają wiele powodów do zmiany i zgodnie z projektem nie można ich rozszerzać. Tak naprawdę powinny istnieć tylko podczas refaktoryzacji jako pośredni cruft.
źródło
class
słowo kluczowe jest używane. Szarpie się jak przestrzeń nazw, chodzi jak przestrzeń nazw - to jedna ...x.equals(y)
ponieważ 1) fakt, że to naprawdę nie powinno modyfikować żadnego stanu, nie jest przekazywany (i nie mogę na tym polegać, nie znając implementacji) 2) Nigdy nie zamierzałem wstawiaćx
" faworyzowane ”lub„ działające ”stanowisko w porównaniu zy
3) Nie chcę brać pod uwagę„ tożsamości ”x
luby
interesują mnie jedynie ich wartości.Przypuszczam, że kiedy zaczyna się robić zło
1) Robi się zbyt duży (w tym przypadku po prostu pogrupuj je w znaczące kategorie).
2) Istnieją metody, które nie powinny być metodami statycznymi
Ale dopóki te warunki nie zostaną spełnione, myślę, że są bardzo przydatne.
źródło
Widget.compareTo(Widget widget)
i statyczneWidgetUtils.compare(Widget widgetOne, Widget widgetTwo)
. Porównanie jest przykładem czegoś, czego nie powinno się robić statycznie.Praktyczna zasada
Możesz spojrzeć na ten problem z dwóch perspektyw:
*Util
metody są często sugestią złego projektu kodu lub leniwej konwencji nazewnictwa.Przykład 1. Prawidłowe wykorzystanie
util
klas / modułów. Przykład biblioteki zewnętrznejZałóżmy, że piszesz aplikację obsługującą pożyczki i karty kredytowe. Dane z tych modułów są udostępniane za pośrednictwem usług internetowych w
json
formacie. Teoretycznie można ręcznie konwertować obiekty na łańcuchy, które będą wjson
środku, ale to wymyśliłoby koło na nowo. Prawidłowym rozwiązaniem byłoby zawarcie w obu modułach zewnętrznej biblioteki służącej do konwersji obiektów java do żądanego formatu. (na przykładowym obrazie pokazałem gson )Przykład 2. Prawidłowe wykorzystanie
util
klas / modułów. Pisanie własnychutil
bez wymówek do innych członków zespołuJako przypadek użycia przyjmijmy, że musimy wykonać jakieś obliczenia w dwóch modułach aplikacji, ale oba muszą wiedzieć, kiedy w Polsce są święta. Teoretycznie możesz wykonać te obliczenia wewnątrz modułów, ale lepiej byłoby wyodrębnić tę funkcjonalność do oddzielnego modułu.
Oto mały, ale ważny szczegół. Klasa / moduł, który napisałeś, nie nazywa się
HolidayUtil
, alePolishHolidayCalculator
. Funkcjonalnie jest toutil
klasa, ale udało nam się uniknąć ogólnego słowa.źródło
Klasy użytkowe są złe, ponieważ oznaczają, że byłeś zbyt leniwy, aby wymyślić lepszą nazwę dla klasy :)
Biorąc to pod uwagę, jestem leniwy. Czasami po prostu musisz wykonać swoją pracę, a twój umysł jest pusty… wtedy zaczynają wkradać się zajęcia z "narzędzi".
źródło
Patrząc teraz wstecz na to pytanie, powiedziałbym, że metody rozszerzające C # całkowicie niszczą potrzebę klas narzędziowych. Ale nie wszystkie języki mają tak genialny konstrukt.
Masz również JavaScript, w którym możesz po prostu dodać nową funkcję bezpośrednio do istniejącego obiektu.
Ale nie jestem pewien, czy naprawdę istnieje elegancki sposób rozwiązania tego problemu w starszym języku, takim jak C ++ ...
Dobry kod obiektowy jest trochę trudny do napisania i trudno go znaleźć, ponieważ pisanie dobrego obiektu obiektowego wymaga dużo więcej czasu / wiedzy niż pisanie przyzwoitego kodu funkcjonalnego.
A kiedy masz ograniczony budżet, twój szef nie zawsze jest zadowolony, widząc, że spędziłeś cały dzień na pisaniu kilku zajęć ...
źródło
Nie do końca zgadzam się, że klasy użytkowe są złe.
Chociaż klasa użytkowa może w pewien sposób naruszać zasady OO, nie zawsze są one złe.
Na przykład wyobraź sobie, że potrzebujesz funkcji, która wyczyści ciąg ze wszystkich podciągów pasujących do wartości
x
.stl c ++ (na razie) nie obsługuje tego bezpośrednio.
Możesz utworzyć polimorficzne rozszerzenie
std::string
.Problem w tym, czy naprawdę chcesz, aby KAŻDY łańcuch, którego używasz w swoim projekcie, był Twoją rozszerzoną klasą ciągów?
Są chwile, kiedy OO tak naprawdę nie ma sensu, a to jest jeden z nich. Chcemy, aby nasz program był kompatybilny z innymi programami, więc będziemy się trzymać
std::string
i tworzyć klasęStringUtil_
(lub coś).Powiedziałbym, że najlepiej jest trzymać się jednego narzędzia na klasę. Powiedziałbym, że głupie jest mieć jedno narzędzie dla wszystkich klas lub wiele narzędzi dla jednej klasy.
źródło
Bardzo łatwo jest oznaczyć coś jako narzędzie tylko dlatego, że projektant nie mógł wymyślić odpowiedniego miejsca na umieszczenie kodu. Często jest kilka prawdziwych „narzędzi”.
Zasadniczo zazwyczaj przechowuję kod w pakiecie, w którym jest używany po raz pierwszy, a następnie przekształcam go w bardziej ogólne miejsce tylko wtedy, gdy stwierdzę, że później jest naprawdę potrzebny gdzie indziej. Jedynym wyjątkiem jest sytuacja, gdy mam już pakiet, który wykonuje podobną / powiązaną funkcjonalność, a kod najlepiej tam pasuje.
źródło
Klasy narzędzi zawierające statyczne metody bezstanowe mogą być przydatne. Testy jednostkowe są często bardzo łatwe.
źródło
Dzięki Java 8 możesz używać statycznych metod w interfejsach ... problem rozwiązany.
źródło
Większość klas Util jest zła, ponieważ:
Istnieją pewne analogie do bibliotek statycznych i dynamicznych.
źródło
Kiedy nie mogę dodać metody do klasy (powiedzmy,
Account
jest zablokowana przed zmianami przez Jr. Developers), po prostu dodaję kilka statycznych metod do mojej klasy Utilities, takich jak:źródło
Account
pliku. Lub lepiej, wybierz nieblokujące się systemy kontroli źródła.Account
plik został zablokowany w taki sposób, że programiści Jr. nie mogą wprowadzać w nim zmian. Jako młodszy programista, aby to obejść, zrobił to, co powyżej. To powiedziawszy, nadal lepiej jest po prostu uzyskać dostęp do zapisu do pliku i zrobić to poprawnie.Klasy użytkowe nie zawsze są złe. Ale powinny zawierać tylko metody, które są wspólne dla szerokiego zakresu funkcji. Jeśli istnieją metody, których można używać tylko w ograniczonej liczbie klas, rozważ utworzenie klasy abstrakcyjnej jako wspólnego rodzica i umieść w niej metody.
źródło