Klasa, która niczego nie reprezentuje - czy jest poprawna?

42

Właśnie projektuję moją aplikację i nie jestem pewien, czy poprawnie rozumiem SOLID i OOP. Klasy powinny robić jedną rzecz i robić to dobrze, ale z drugiej strony powinny reprezentować rzeczywiste obiekty, z którymi pracujemy.

W moim przypadku przeprowadzam ekstrakcję funkcji w zbiorze danych, a następnie analizuję uczenie maszynowe. Zakładam, że mógłbym stworzyć trzy klasy

  1. FeatureExtractor
  2. DataSet
  3. Analizator

Ale klasa FeatureExtractor nic nie reprezentuje, robi coś, co czyni ją bardziej rutynową niż klasą. Będzie miał tylko jedną funkcję, która będzie używana: extract_features ()

Czy poprawne jest tworzenie klas, które nie reprezentują jednej rzeczy, ale robią jedną?

EDYCJA: nie jestem pewien, czy to ważne, ale używam Pythona

A jeśli ekstrakt_features () wyglądałby tak: czy warto stworzyć specjalną klasę do przechowywania tej metody?

def extract_features(df):
    extr = PhrasesExtractor()
    extr.build_vocabulary(df["Text"].tolist())

    sent = SentimentAnalyser()
    sent.load()

    df = add_features(df, extr.features)
    df = mark_features(df, extr.extract_features)
    df = drop_infrequent_features(df)
    df = another_processing1(df)
    df = another_processing2(df)
    df = another_processing3(df)
    df = set_sentiment(df, sent.get_sentiment)
    return df
Alicja Głowacka
źródło
13
Wygląda to doskonale jako funkcja. Biorąc pod uwagę trzy rzeczy wymienione jako moduły, jest w porządku i możesz chcieć umieścić je w różnych plikach, ale to nie znaczy, że muszą to być klasy.
Bergi,
31
Pamiętaj, że w Pythonie jest dość powszechne i dopuszczalne stosowanie metod innych niż OO.
jpmc26
13
Możesz być zainteresowany projektowaniem opartym na domenach. „Klasy powinny reprezentować obiekty ze świata rzeczywistego” są w rzeczywistości fałszywe ... powinny reprezentować obiekty w domenie . Domena jest często silnie powiązana ze światem rzeczywistym, ale w zależności od aplikacji pewne rzeczy mogą, ale nie muszą być uważane za przedmioty, lub niektóre rzeczy, które „w rzeczywistości” są oddzielne, mogą być połączone lub identyczne w domenie aplikacji.
Bakuriu
1
Gdy poznasz OOP, myślę, że zauważysz, że klasy bardzo rzadko korespondują jeden na jeden z bytami z prawdziwego świata. Na przykład, tutaj jest esej, który dowodzi, że próba wbicia całej funkcjonalności związanej z bytem świata rzeczywistego w pojedynczej klasie jest bardzo często anty-wzorcem: programmer.97things.oreilly.com/wiki/index.php/…
Kevin - Przywróć Monikę
1
„powinny reprezentować prawdziwe obiekty, z którymi współpracujemy”. niekoniecznie. Wiele języków ma klasę strumienia reprezentującą strumień bajtów, który jest abstrakcyjnym pojęciem, a nie „prawdziwym obiektem”. Technicznie system plików też nie jest „prawdziwym obiektem”, to tylko koncepcja, ale czasami istnieją klasy reprezentujące system plików lub jego część.
Pharap

Odpowiedzi:

96

Klasy powinny zrobić jedną rzecz i zrobić to dobrze

Tak, to ogólnie dobre podejście.

ale z drugiej strony powinny reprezentować prawdziwy obiekt, z którym pracujemy.

Nie, to powszechne nieporozumienie IMHO. To prawda, że dobry dostęp początkującego do OOP często „zaczyna się od przedmiotów reprezentujących rzeczy z prawdziwego świata” .

Jednak nie powinieneś na tym poprzestać !

Klasy mogą (i powinny) być wykorzystywane do strukturyzacji twojego programu na różne sposoby. Modelowanie obiektów z realnego świata jest jednym z aspektów, ale nie jedynym. Tworzenie modułów lub komponentów dla konkretnego zadania to kolejny rozsądny przypadek użycia klas. „Moduł wyodrębniający funkcje” jest prawdopodobnie takim modułem i nawet jeśli zawiera tylko jedną metodę publicznąextract_features() , byłbym zdziwiony, gdyby nie zawierał również wielu metod prywatnych i być może jakiegoś wspólnego stanu. Posiadanie klasy FeatureExtractorwprowadzi naturalną lokalizację dla tych prywatnych metod.

Uwaga dodatkowa: w językach takich jak Python, które obsługują osobną koncepcję modułu, można do tego również użyć modułu FeatureExtractor, ale w kontekście tego pytania jest to IMHO znikoma różnica.

Co więcej, „ekstraktor funkcji” można wyobrazić sobie jako „osobę lub bota, który wyodrębnia funkcje”. To abstrakcyjna „rzecz”, być może nie taka, którą można znaleźć w prawdziwym świecie, ale sama nazwa jest przydatną abstrakcją, która daje wszystkim wyobrażenie o odpowiedzialności tej klasy. Nie zgadzam się więc, że ta klasa niczego nie „reprezentuje”.

Doktor Brown
źródło
33
Szczególnie podoba mi się to, że wspomniał pan o kwestii stanu wewnętrznego. Często uważam, że jest to decydujący czynnik decydujący o tym, czy utworzę coś w klasie czy funkcji w Pythonie.
David Z
17
Wydaje się, że polecasz „zapalenie klasy”. Nie twórz do tego klasy, jest to antipattern w stylu Java. Jeśli jest to funkcja, uczyń ją funkcją. Stan wewnętrzny jest nieistotny: funkcje mogą to mieć (poprzez zamknięcia).
Konrad Rudolph,
25
@KonradRudolph: zdaje się, że tęsknisz za tym, że nie chodzi o wykonanie jednej funkcji. Chodzi o fragment kodu, który wymaga kilku funkcji, wspólnej nazwy i być może wspólnego stanu. Używanie do tego modułu może być sensowne w językach z koncepcją modułu oprócz klas.
Doc Brown
8
@DocBrown Będę musiał się nie zgodzić. To klasa z jedną publiczną metodą. Jeśli chodzi o API, to nie do odróżnienia od funkcji. Zobacz moją odpowiedź, aby poznać szczegóły. Użycie klas pojedynczej metody może być uzasadnione, jeśli trzeba utworzyć określony typ reprezentujący stan. Ale tutaj tak nie jest (i nawet wtedy funkcje mogą być czasami używane).
Konrad Rudolph
6
@DocBrown Zaczynam rozumieć, co masz na myśli: mówisz o funkcjach wywoływanych od wewnątrz extract_features? Po prostu założyłem, że były to funkcje publiczne z innego miejsca. W porządku, zgadzam się, że jeśli są one prywatne, to prawdopodobnie powinny wejść do modułu (ale nadal: nie do klasy, chyba że dzielą państwo), razem z extract_features. (To powiedziawszy, można oczywiście zadeklarować je lokalnie w ramach tej funkcji.)
Konrad Rudolph
44

Doc Brown jest na miejscu: klasy nie muszą reprezentować obiektów z prawdziwego świata. Po prostu muszą być przydatne . Klasy są zasadniczo jedynie dodatkowe typy, a co robi intlub stringodpowiadają w realnym świecie? Są to abstrakcyjne opisy, a nie konkretne, namacalne rzeczy.

To powiedziawszy, twoja sprawa jest wyjątkowa. Zgodnie z Twoim opisem:

A jeśli ekstrakt_features () wyglądałby tak: czy warto stworzyć specjalną klasę do przechowywania tej metody?

Masz całkowitą rację: jeśli kod jest taki, jak pokazano, nie ma sensu przekształcać go w klasę. Istnieje słynna przemowa, która dowodzi, że takie zastosowania klas w Pythonie mają zapach kodu i że proste funkcje są często wystarczające. Twoja sprawa jest tego doskonałym przykładem.

Nadużywanie klas wynika z faktu, że OOP stał się głównym nurtem Java w latach 90. Niestety w Javie brakowało wówczas kilku nowoczesnych funkcji językowych (takich jak zamknięcia), co oznacza, że ​​wiele pojęć było trudnych lub niemożliwych do wyrażenia bez użycia klas. Na przykład w Javie do niedawna niemożliwe było posiadanie metod, które niosły stan (tj. Zamknięcia). Zamiast tego trzeba było napisać klasę, która będzie nosiła stan, i która ujawniła jedną metodę (zwaną coś w rodzaju invoke).

Niestety ten styl programowania stał się popularny znacznie poza Javą (częściowo z powodu wpływowej książki o inżynierii oprogramowania, która poza tym jest bardzo przydatna), nawet w językach, które nie wymagają takich obejść.

W Pythonie klasy są oczywiście bardzo ważnym narzędziem i powinny być używane swobodnie. Ale nie są jedynym narzędziem i nie ma powodu, aby używać ich tam, gdzie nie mają sensu. To powszechne błędne przekonanie, że w funkcjach wolnych nie ma miejsca w OOP.

Konrad Rudolph
źródło
Przydałoby się dodać, że jeśli funkcje wywoływane w tym przykładzie są w rzeczywistości funkcjami prywatnymi, kapsułkowanie ich w module lub klasie byłoby całkowicie odpowiednie. W przeciwnym razie zgadzam się całkowicie.
Leliel,
11
Warto również pamiętać, że „OOP” nie oznacza „napisz kilka klas”. Funkcje są obiektami w Pythonie, więc nie trzeba uważać tego za „nie OOP”. Raczej po prostu ponownie wykorzystuje wbudowane typy / klasy, a „ponowne użycie” jest jednym ze świętych Graali w programowaniu. Zawinięcie tego w klasie uniemożliwiłoby ponowne użycie, ponieważ nic nie byłoby kompatybilne z tym nowym API (chyba że __call__zdefiniowano, w takim przypadku wystarczy użyć funkcji!)
Warbo 16.04.18
3
Również na temat „zajęć a funkcje wolnostojące”: eev.ee/blog/2013/03/03/…
Joker_vD
1
Czy nie jest tak, że w Pythonie „wolne funkcje” to także obiekty z typem ujawniającym metodę __call__()? Czy to naprawdę tak różni się od anonimowej instancji klasy wewnętrznej? Składniowo, jasne, ale z projektu językowego, wydaje się to mniej znaczące rozróżnienie niż tutaj.
JimmyJames
1
@JimmyJames Right. Chodzi o to, że oferują one tę samą funkcjonalność do określonego celu, ale są prostsze w użyciu.
Konrad Rudolph
36

Właśnie projektuję moją aplikację i nie jestem pewien, czy poprawnie rozumiem SOLID i OOP.

Byłem w tym przez ponad 20 lat i nie jestem też pewien.

Klasy powinny zrobić jedną rzecz i zrobić to dobrze

Trudno się tutaj pomylić.

powinny reprezentować prawdziwe obiekty, z którymi pracujemy.

Naprawdę? Pozwól, że przedstawię ci pojedynczy najbardziej popularnych i udanych klasie wszechczasów: String. Używamy go do tekstu. A rzeczywisty obiekt, który reprezentuje to:

Rybak trzyma 10 ryb zawieszonych na sznurku

Dlaczego nie, nie wszyscy programiści mają obsesję na punkcie połowów. Używamy tutaj czegoś, co nazywa się metaforą. Można tworzyć modele rzeczy, które tak naprawdę nie istnieją. To pomysł, który musi być jasny. Tworzysz obrazy w myślach swoich czytelników. Te obrazy nie muszą być prawdziwe. Po prostu łatwo zrozumiałe.

Dobry projekt OOP grupuje komunikaty (metody) wokół danych (stanu), dzięki czemu reakcje na te komunikaty mogą się różnić w zależności od tych danych. Jeśli to robi, modeluje jakieś rzeczy z prawdziwego świata, bzdurne. Jeśli nie, to dobrze. O ile ma to sens dla czytelnika, jest w porządku.

Teraz możesz pomyśleć o tym w ten sposób:

Świąteczne litery zawieszone na sznurku brzmią „LETS THINGS THINGS!”

ale jeśli uważasz, że to musi istnieć w prawdziwym świecie, zanim będziesz mógł skorzystać z tej metafory, to dobrze, twoja kariera programistyczna będzie wymagała wielu sztuk i rzemiosła.

candied_orange
źródło
1
Całkiem ciąg zdjęć ...
Zev Spitz
W tym momencie nie jestem pewien, czy „sznurek” jest nawet metaforyczny. Ma tylko określone znaczenie w dziedzinie programowania, podobnie jak słowa takie jak classi tablei column...
Kyralessa
@ Kyralessa, jesteś eterem, naucz początkującą metaforę lub pozwól im być magią. Proszę, ocal mnie od programistów, którzy wierzą w magię.
candied_orange
6

Strzec się! Nigdzie SOLID nie mówi, że klasa powinna „robić tylko jedną rzecz”. Gdyby tak było, klasy miałyby tylko jedną metodę i tak naprawdę nie byłoby różnicy między klasami a funkcjami.

SOLID mówi, że klasa powinna reprezentować jedną odpowiedzialność . Są one trochę jak obowiązki osób w zespole: kierowca, prawnik, kieszonkowiec, grafik itp. Każda z tych osób może wykonywać wiele (powiązanych) zadań, ale wszystkie dotyczą jednej odpowiedzialności.

Chodzi o to, że jeśli nastąpi zmiana wymagań, najlepiej zmodyfikować tylko jedną klasę. Dzięki temu kod jest łatwiejszy do zrozumienia, łatwiejszy do modyfikacji i zmniejsza ryzyko.

Nie ma zasady, że obiekt powinien reprezentować „prawdziwą rzecz”. To tylko wiedza o kulturze ładunkowej, odkąd OO został pierwotnie wynaleziony do zastosowania w symulacjach. Ale twój program nie jest symulacją (jest kilka nowoczesnych aplikacji OO), więc ta zasada nie ma zastosowania. Tak długo, jak każda klasa ma jasno określoną odpowiedzialność, powinieneś czuć się dobrze.

Jeśli klasa naprawdę ma tylko jedną metodę, a klasa nie ma żadnego stanu, można rozważyć utworzenie z niej funkcji autonomicznej. Jest to z pewnością w porządku i zgodne z zasadami KISS i YAGNI - nie trzeba tworzyć klasy, jeśli można ją rozwiązać za pomocą funkcji. Z drugiej strony, jeśli masz powody, by sądzić, że potrzebujesz wewnętrznego stanu lub wielu implementacji, równie dobrze możesz uczynić z niej klasę z góry. Będziesz musiał tutaj wykorzystać swój najlepszy osąd.

JacquesB
źródło
+1 za „nie trzeba tworzyć klasy, jeśli można ją rozwiązać za pomocą funkcji”. Czasami ktoś musi mówić prawdę.
tchrist
5

Czy poprawne jest tworzenie klas, które nie reprezentują jednej rzeczy, ale robią jedną?

Ogólnie to jest OK.

Bez nieco bardziej szczegółowego opisu, co FeatureExtractordokładnie ma zrobić klasa, trudno powiedzieć.

W każdym razie, nawet jeśli FeatureExtractorujawnia tylko funkcję publiczną extract_features(), mógłbym pomyśleć o skonfigurowaniu jej z Strategyklasą, która określa, jak dokładnie należy wyodrębnić.

Innym przykładem jest klasa z funkcją szablonu .

I jest więcej wzorów wzorców behawioralnych , które są oparte na modelach klas.


W miarę dodawania kodu w celu wyjaśnienia.

A jeśli ekstrakt_features () wyglądałby tak: czy warto stworzyć specjalną klasę do przechowywania tej metody?

Linia

 sent = SentimentAnalyser()

dokładnie obejmuje to, co miałem na myśli, że możesz skonfigurować klasę ze Strategią .

Jeśli masz interfejs dla tej SentimentAnalyserklasy, możesz przekazać ją do FeatureExtractorklasy w jej punkcie konstrukcyjnym, zamiast bezpośrednio łączyć się z tą konkretną implementacją w swojej funkcji.

πάντα ῥεῖ
źródło
2
Nie widzę powodu, aby dodawać złożoność ( FeatureExtractorklasę) tylko po to, aby wprowadzić jeszcze większą złożoność (interfejs dla SentimentAnalyserklasy). Jeśli pożądane jest odsprzęgnięcie, wówczas extract_featuresmoże przyjąć get_sentimentfunkcję jako argument ( loadwywołanie wydaje się być niezależne od funkcji i wywoływane tylko dla jej efektów). Zauważ też, że Python nie ma / zachęca interfejsów.
Warbo
1
@ warbo - nawet jeśli podasz funkcję jako argument, czyniąc ją funkcją, ograniczasz potencjalne implementacje, które będą pasowały do ​​formatu funkcji, ale jeśli zachodzi potrzeba zarządzania stanem trwałym między jednym wywołaniem a następnie (np. a CacheingFeatureExtractorlub a TimeSeriesDependentFeatureExtractor) wtedy obiekt będzie znacznie lepiej dopasowany. To, że obiekt nie jest obecnie potrzebny , nie oznacza, że ​​nigdy go nie będzie.
Jules
3
@Jules Po pierwsze, nie będziesz go potrzebował (YAGNI), po drugie funkcje Pythona mogą odwoływać się do stanu trwałego (zamknięcia), jeśli go potrzebujesz (nie będziesz), po trzecie użycie funkcji nie ogranicza niczego, ponieważ żaden obiekt z __call__metoda będzie kompatybilna, jeśli będziesz jej potrzebować (nie będziesz tego potrzebować), po czwarte, dodając opakowanie, tak FeatureExtractorjakbyś robił kod niezgodnym z całym innym kodem, jaki kiedykolwiek napisano (chyba że podasz __call__metodę, w którym to przypadku funkcja byłaby znacznie prostsza )
Warbo
0

Poza wzorami i całym wymyślnym językiem / koncepcjami: natknąłeś się na zadanie lub proces wsadowy .

Pod koniec dnia nawet czysty program OOP musi jakoś być napędzany przez coś, aby faktycznie wykonywać pracę; musi być jakiś punkt wejścia. Na przykład we wzorze MVC kontroler „C” odbiera zdarzenia kliknięcia itp. Z GUI, a następnie koordynuje inne komponenty. W klasycznych narzędziach wiersza poleceń funkcja „główna” zrobiłaby to samo.

Czy poprawne jest tworzenie klas, które nie reprezentują jednej rzeczy, ale robią jedną?

Twoja klasa reprezentuje byt, który coś robi i aranżuje wszystko inne. Możesz nazwać to Controller , Job , Main lub cokolwiek, co ci się przyśni.

A jeśli ekstrakt_features () wyglądałby tak: czy warto stworzyć specjalną klasę do przechowywania tej metody?

To zależy od okoliczności (i nie znam zwykłego sposobu, w jaki odbywa się to w Pythonie). Jeśli jest to tylko małe narzędzie wiersza poleceń, metoda zamiast klasy powinna być w porządku. Na pewno pierwsza wersja twojego programu może uciec. Jeśli później okaże się, że otrzymujesz dziesiątki takich metod, być może nawet przy pomieszanych zmiennych globalnych, nadszedł czas, aby przefiltrować klasy.

AnoE
źródło
3
Należy pamiętać, że w takich scenariuszach nazywanie samodzielnych procedur „metodami” może być mylące. Większość języków, w tym Python, nazywa je „funkcjami”. „Metody” to funkcje / procedury powiązane z konkretnym wystąpieniem klasy, co jest przeciwieństwem użycia tego terminu :)
Warbo
To prawda, @Warbo. Lub moglibyśmy nazwać je procedurą, odrzuceniem lub sub lub…; i mogą to być metody klasowe (sic) niezwiązane z instancją. Mam nadzieję, że łagodny czytelnik będzie w stanie wyrenderować zamierzone znaczenie. :)
AnoE
@Warbo, które warto wiedzieć! Większość materiałów do nauki, z którymi się spotkałem, stwierdza, że ​​funkcje i metody terminów są wymienne i że jest to tylko preferencja zależna od języka.
Dom
@Dom Ogólnie funkcja („czysta”) to odwzorowanie wartości wejściowych na wartości wyjściowe; „procedura” to funkcja, która może również powodować efekty (np. usuwanie pliku); oba są wysyłane statycznie (tzn. sprawdzane w zakresie leksykalnym). „Metoda” jest funkcją lub (zwykle) procedurą, która jest dynamicznie wysyłana (sprawdzana) z wartości (zwanej „obiektem”), która jest automatycznie powiązana z (domyślnym thislub jawnym self) argumentem metody. Metody obiektu są wzajemnie „otwarcie” rekurencyjne, więc zastąpienie foopowoduje, że wszystkie self.foowywołania korzystają z tego zastąpienia.
Warbo,
0

Możemy myśleć o OOP jako o modelowaniu zachowania systemu. Zauważ, że system nie musi istnieć w „prawdziwym świecie”, chociaż metafory w świecie rzeczywistym mogą czasem być przydatne (np. „Rurociągi”, „fabryki” itp.).

Jeśli nasz pożądany system jest zbyt skomplikowany, aby modelować go od razu, możemy go rozbić na mniejsze części i modelować te („dziedzina problemowa”), co może wymagać dalszego podziału, i tak dalej, aż dojdziemy do kawałków, których zachowanie się zgadza (mniej więcej) dla niektórych wbudowanych obiektów językowych, takich jak liczba, ciąg znaków, lista itp.

Po uzyskaniu tych prostych elementów możemy połączyć je razem, aby opisać zachowanie większych elementów, które możemy połączyć razem w jeszcze większe kawałki i tak dalej, dopóki nie będziemy w stanie opisać wszystkich składników domeny, które są potrzebne dla całości system.

W tej fazie „łączenia się” możemy napisać niektóre klasy. Piszemy klasy, gdy nie ma istniejącego obiektu, który zachowuje się tak, jak chcemy. Na przykład nasza domena może zawierać „foos”, kolekcje foos zwane „batonami” i kolekcje batoników nazywanych „bazami”. Możemy zauważyć, że foos są wystarczająco proste do modelowania za pomocą łańcuchów, więc to robimy. Okazuje się, że paski wymagają, aby ich zawartość była zgodna z określonym ograniczeniem, które nie pasuje do niczego, co zapewnia Python, w takim przypadku możemy napisać nową klasę w celu wymuszenia tego ograniczenia. Być może bazy nie mają takich osobliwości, więc możemy po prostu przedstawić je za pomocą listy.

Zauważ, że moglibyśmy napisać nową klasę dla każdego z tych składników (foos, barów i baz), ale nie musimy, jeśli jest już coś z prawidłowym zachowaniem. W szczególności, aby klasa była użyteczna, musi „dostarczyć” coś (dane, metody, stałe, podklasy itp.), Więc nawet jeśli mamy wiele warstw klas niestandardowych, musimy w końcu użyć wbudowanej funkcji; na przykład, gdybyśmy napisali nową klasę dla foos, prawdopodobnie zawierałaby ona tylko ciąg znaków, więc dlaczego nie zapomnieć o klasie foo i pozwolić, aby klasa bar zawierała te łańcuchy zamiast tego? Pamiętaj, że klasy są również wbudowanym obiektem, są one szczególnie elastyczne.

Kiedy już mamy nasz model domeny, możemy wziąć pewne szczególne przykłady tych elementów i ustawić je w „symulacji” konkretnego systemu, który chcemy modelować (np. „System uczenia maszynowego dla ...”).

Kiedy już mamy tę symulację, możemy ją uruchomić i hej presto, mamy działający (symulacja) system uczenia maszynowego dla ... (lub cokolwiek, co modelowaliśmy).


Teraz, w twojej konkretnej sytuacji, próbujesz modelować zachowanie komponentu „ekstraktora funkcji”. Pytanie brzmi: czy są jakieś wbudowane obiekty, które zachowują się jak „ekstraktor funkcji”, czy może trzeba je rozbić na prostsze rzeczy? Wygląda na to, że ekstraktory funkcji zachowują się bardzo podobnie do obiektów funkcyjnych, więc myślę, że możesz użyć ich jako modelu.


Jedną z rzeczy, o których należy pamiętać, ucząc się o tego rodzaju pojęciach, jest to, że różne języki mogą zapewniać różne wbudowane funkcje i obiekty (i oczywiście niektóre nie używają nawet terminologii takiej jak „obiekty”!). Dlatego rozwiązania, które mają sens w jednym języku, mogą być mniej przydatne w innym (może to nawet dotyczyć różnych wersji tego samego języka!).

Historycznie wiele literatury dotyczącej OOP (szczególnie „wzorce projektowe”) koncentrowało się na Javie, która jest zupełnie inna niż Python. Na przykład klasy Java nie są obiektami, Java do niedawna nie miała obiektów funkcyjnych, Java ma ścisłe sprawdzanie typów (co zachęca do tworzenia interfejsów i podklas), podczas gdy Python zachęca do pisania kaczego, Java nie ma obiektów modułowych, liczb całkowitych Java / floats / etc. nie są obiektami, metaprogramowanie / introspekcja w Javie wymaga „refleksji” i tak dalej.

Nie próbuję wybierać na Javie (jako inny przykład, wiele teorii OOP obraca się wokół Smalltalk, który znowu bardzo różni się od Pythona), po prostu próbuję wskazać, że musimy bardzo uważnie przemyśleć kontekst i ograniczenia, w których opracowano rozwiązania, i czy pasuje to do sytuacji, w której się znajdujemy.

W twoim przypadku obiekt funkcji wydaje się dobrym wyborem. Jeśli zastanawiasz się, dlaczego niektóre wytyczne dotyczące najlepszych praktyk nie wspominają o obiektach funkcyjnych jako możliwym rozwiązaniu, być może dlatego, że te wytyczne zostały napisane dla starych wersji Java!

Warbo
źródło
0

Pragmatycznie rzecz biorąc, kiedy mam „różne rzeczy, które robią coś ważnego i powinny być oddzielne” i nie mają wyraźnego domu, umieszczam to w Utilitiessekcji i używam tego jako mojej konwencji nazewnictwa. to znaczy. FeatureExtractionUtility.

Zapomnij o liczbie metod w klasie; jedna dzisiejsza metoda może wymagać jutro pięciu metod. Liczy się jasna i spójna struktura organizacyjna, taka jak obszar narzędziowy dla różnych zbiorów funkcji.

Dom
źródło