Czasami tworzę klasy „Util”, które służą przede wszystkim do przechowywania metod i wartości, które tak naprawdę nie wydają się należeć gdzie indziej. Ale za każdym razem, gdy tworzę jedną z tych klas, myślę „uh, och, później będę tego żałować ...”, ponieważ czytam gdzieś, że jest źle.
Ale z drugiej strony wydaje się, że istnieją dla nich dwa przekonujące (przynajmniej dla mnie) przypadki:
- tajniki implementacji używane w wielu klasach w pakiecie
- zapewniając użyteczną funkcjonalność w celu zwiększenia klasy, bez zaśmiecania jej interfejsu
Czy jestem w drodze do zniszczenia? Co mówisz !! Czy powinienem refaktoryzować?
Util
w nazwach swoich klas. Problem rozwiązany.SomethingUtil
jest nieco leniwe i po prostu przesłania jej prawdziwy cel - podobnie jak w przypadku klas o nazwachSomethingManager
lubSomethingService
. Jeśli ta klasa ma jedną odpowiedzialność, powinno być łatwo nadać jej sensowną nazwę. Jeśli nie, to jest to prawdziwy problem do rozwiązania ...Util
, ale oczywiście nie spodziewałem się, że to zostanie naprawione, a reszta pytania zostanie zignorowana ...Odpowiedzi:
Nowoczesne wzornictwo OO akceptuje, że nie wszystko jest przedmiotem. Niektóre rzeczy są zachowaniami lub formułami, a niektóre nie mają stanu. Dobrze jest modelować te rzeczy jako czyste funkcje, aby uzyskać korzyści z tego projektu.
Java i C # (i inne) wymagają stworzenia klasy util i przeskoczenia przez ten obręcz, aby to zrobić. Irytujące, ale nie koniec świata; i niezbyt kłopotliwe z punktu widzenia projektowania.
źródło
Nigdy nie mów nigdy"
Nie sądzę, że to musi być złe, tylko źle, jeśli zrobisz to źle i nadużyjesz.
Wszyscy potrzebujemy narzędzi i narzędzi
Na początek wszyscy używamy bibliotek, które czasami są uważane za prawie wszechobecne i niezbędne. Na przykład w świecie Java, Google Guava lub niektórych Apache Commons ( Apache Commons Lang , Apache Commons Collections itp.).
Tak więc wyraźnie jest taka potrzeba.
Unikaj twardych słów, powielania i wprowadzania błędów
Jeśli myślisz o nich dość dużo po prostu bardzo duże grono tych
Util
klas można opisać, chyba ktoś przeszedł wiele trudu, aby je (stosunkowo) prawo, a oni byli razem - przetestowany i mocno przyciągające zaciskał przez innych.Powiedziałbym więc, że pierwszą zasadą przy odczuciu swędzenia pisania
Util
zajęć jest sprawdzenie, czyUtil
klasa faktycznie nie istnieje.Jedynym kontrargumentem, jaki widziałem, jest to, że chcesz ograniczyć swoje zależności, ponieważ:
Ale z obydwoma tymi problemami można zająć się ponownie pakując bibliotekę przy użyciu ProGuard lub jej odpowiednika, lub osobiście ją rozłączając (dla użytkowników Maven wtyczka maven-shadow-plug oferuje pewne wzorce filtrowania, aby zintegrować to jako część twojej kompilacji).
Więc jeśli jest w wersji lib i pasuje do twojego przypadku użycia, a żadne testy porównawcze nie wskazują inaczej, użyj go. Jeśli różni się on nieco od tego, co przedłużysz, przedłuż go (jeśli to możliwe) lub przedłuż, albo w ostateczności przepisz go.
Konwencje nazewnictwa
Jednak do tej pory w tej odpowiedzi nazwałem ich
Util
podobnymi do ciebie. Nie nazywaj ich tak.Nadaj im sensowne nazwy. Weź Google Guava jako (bardzo, bardzo) dobry przykład tego, co należy zrobić, i wyobraź sobie, że
com.google.guava
przestrzeń nazw jest tak naprawdę Twoimutil
katalogiem głównym.Zadzwoń do swojego pakietu
util
, w najgorszym wypadku, ale nie do klas. Jeśli dotyczyString
obiektów i manipulacji konstruktów smyczkowych, nazwaćStrings
, a nieStringUtils
(przepraszam, Apache Commons Lang - nadal lubię cię i używać!). Jeśli robi coś konkretnego, wybierz nazwę konkretnej klasy (jakSplitter
lubJoiner
).Test jednostkowy
Jeśli musisz użyć tych narzędzi, przetestuj je. Zaletą narzędzi jest to, że zwykle są to raczej samodzielne komponenty, które pobierają określone dane wejściowe i zwracają określone dane wyjściowe. To jest koncepcja. Nie ma więc wymówki, aby ich nie testować jednostkowo.
Ponadto testy jednostkowe pozwolą ci zdefiniować i udokumentować umowę API. Jeśli testy zakończą się, albo zmieniłeś coś w niewłaściwy sposób, albo oznacza to, że próbujesz zmienić umowę API (lub że twoje oryginalne testy były badziewne - ucz się z tego i nie rób tego ponownie) .
Projektowanie interfejsu API
Decyzje projektowe, które podejmiesz dla tych interfejsów API, prawdopodobnie podążą za tobą długo. Tak więc, nie poświęcając godzin na pisanie
Splitter
-klonu, uważaj na swoje podejście do problemu.Zadaj sobie kilka pytań:
Chcesz, aby te narzędzia obejmowały szeroki wachlarz przypadków użycia, były solidne, stabilne, dobrze udokumentowane, zgodnie z zasadą najmniejszego zaskoczenia i były niezależne. Idealnie byłoby, gdyby każdy podpakiet twoich narzędzi, lub przynajmniej cały pakiet użytkowy, mógł zostać wyeksportowany do pakietu w celu łatwego ponownego użycia.
Jak zwykle ucz się od gigantów tutaj:
util
Pakiet Java (który zawiera bibliotekę Kolekcje) i jego odpowiednik .Net ,Tak, wiele z nich kładzie nacisk na kolekcje i struktury danych, ale nie mów mi, że nie jest to miejsce lub po co zwykle możesz wdrożyć większość swoich narzędzi, bezpośrednio lub pośrednio.
źródło
If deals with String objects and manipulation of string constructs, call it Strings, not StringUtils
StringsCollectionTypeHere
jeśli chcesz konkretnej implementacji. Lub bardziej konkretna nazwa, jeśli ciągi te mają określone znaczenie w kontekście Twojej aplikacji. W tym konkretnym przypadku Guava używaStrings
swoich pomocników związanych z łańcuchami, w przeciwieństwie doStringUtils
Commons Lang. Uważam to za całkowicie akceptowalne, oznacza to dla mnie, że klasy obsługująString
obiekt lub są klasą ogólnego przeznaczenia do zarządzania ciągami.NameUtils
rzecz biorąc , błąd mnie bez końca, ponieważ jeśli znajduje się pod wyraźnie oznaczoną nazwą pakietu, wiedziałbym już, że jest to klasa narzędziowa (a jeśli nie, szybko to zrozumiałbym po spojrzeniu na API). To tak irytujące dla mnie jako osoby deklarując rzeczy jakSomethingInterface
,ISomething
lubSomethingImpl
. Nieźle sobie radziłem z takimi artefaktami, gdy kodowałem w C i nie używałem IDE. Dzisiaj generalnie nie potrzebuję takich rzeczy.Klasy Util nie są spójne i generalnie mają zły projekt, ponieważ klasa musi mieć jeden powód do zmiany (zasada pojedynczej odpowiedzialności).
Jednak widziałem „util” klas w samym Java API, takich jak:
Math
,Collections
iArrays
.Są to w rzeczywistości klasy użytkowe, ale wszystkie ich metody są powiązane z jednym tematem, jedna ma operacje matematyczne, jedna ma metody manipulowania kolekcjami, a druga do manipulowania tablicami.
Staraj się nie mieć całkowicie niepowiązanych metod w klasie użyteczności. W takim przypadku istnieje szansa, że równie dobrze możesz umieścić je tam, gdzie naprawdę są.
Jeśli musi mieć util klas następnie spróbuj im być oddzielone tematu jak Java
Math
,Collections
iArrays
. Przynajmniej pokazuje pewien zamiar projektowania, nawet jeśli są to tylko przestrzenie nazw.I dla jednego, zawsze unikać klas użytkowych i nigdy nie miałem potrzeby , aby utworzyć.
źródło
Math
lubArrays
pokazuje przynajmniej pewne zamiary projektu.Jest całkiem akceptowalny, aby mieć klasy użytkowe , chociaż wolę ten termin
ClassNameHelper
. .NET BCL zawiera nawet klasy pomocnicze. Najważniejszą rzeczą do zapamiętania jest dokładne udokumentowanie celu zajęć, a także każdej metody pomocnika oraz uczynienie z niego wysokiej jakości kodu, który można utrzymać.I nie daj się zwieść klasom pomocników.
źródło
Używam dwupoziomowego podejścia. Klasa „Globals” w pakiecie „util” (folder). Aby coś przejść do klasy „Globals” lub pakietu „util”, musi to być:
Przykłady, które pomyślnie przejdą te testy:
Oto przykład bardzo małej metody pomocniczej, całkowicie niezależnej od reszty aplikacji:
Patrząc na to, widzę błąd, w którym 21 powinno być „21”, 22 powinno być „22.” itd., Ale to nie ma sensu.
Jeśli jedna z tych metod pomocniczych rośnie lub staje się skomplikowana, należy ją przenieść do własnej klasy w pakiecie użytkownika. Jeśli dwie lub więcej klas pomocniczych w pakiecie użytkownika są ze sobą powiązane, należy je przenieść do własnego pakietu. Jeśli metoda stała lub pomocnicza okaże się związana z określoną częścią aplikacji, należy ją tam przenieść.
Powinieneś być w stanie uzasadnić, dlaczego nie ma lepszego miejsca na wszystko, co trzymasz w klasie Globals lub pakiecie użytkownika, i powinieneś czyścić je okresowo za pomocą powyższych testów. W przeciwnym razie po prostu tworzysz bałagan.
źródło