Cześć wszystkim, przepraszam za trochę przewrotne pytanie. Przesiadłem się z dość mało znanego języka MQL4 na Java i czegoś nie rozumiem. Posilę się przykładem. Chciałbym dokonać kilkunastu różnych obliczeń i z tego co widzę na kursach online, wszyscy tworzą oddzielną klasę lub kilka klas do przeprowadzania żądanych obliczeń. W tych klasach znajdują się metody itd. Pytanie: czy zamiast tworzyć dodatkowe klasy wraz z metodami nie dałoby się stworzyć kilka metod w głównej klasie main i tylko w odpowiednim momencie kodu wywołać daną metodę żeby zwróciła nam wynik?
Dałoby się.
Dla prostych programów to co mówisz jest najlepsze. Jedna klasa, metoda main
i reszta w statycznych metodach. Podział na klasy ma sens im większy jest twój kod. Tak samo jak funkcja pozwala na użycie tego samego kodu w różnych sytuacjach (masz funkcję sin(x)
przez co nie musisz liczyć tego ręcznie jak i możesz użyć gotowca) tak klasa pozwala na użycie kodu z różnych stanem (każda instancja ma inny stan) w różnych sytuacjach. Np. klasa HashMap
pozwala na stworzenie mapowania z X -> Y
co bardzo często się przydaje. Możesz jest użyć jako słownik polsko-angielski albo do trzymania informacji w stylu jakie jest ulubione danie danej osoby
Projektowanie obiektowe jest trudne i początkujący zazwyczaj nie ogarniają jak to robić. To co się uczy na kursach jest często kontrproduktywne i dopiero praktyka uczy potrzebnego doświadczenia i intuicji,
Na sam początek zajmij się klepaniem wszystkiego w jednej klasie, później możesz poczytać na czym polega programowanie obiektowe. Część rzeczy wyłapiesz intuicyjnie np. fakt, że klasy dostępne w bibliotece standardowej takie jak String
są przydatne, bo ukrywają złożoność kodu w zgrabnym interfejsie i nie musisz odkrywać koła na nowo
Pytanie: czy zamiast tworzyć dodatkowe klasy wraz z metodami nie dałoby się stworzyć kilka metod w głównej klasie main i tylko w odpowiednim momencie kodu wywołać daną metodę żeby zwróciła nam wynik?
Robiąc wszystko w jednej głównej klasie łatwo ci się zrobi chaos. Ale to trzeba poczuć. Samemu popracować z czymś większym.
Dlatego ludzie dzielą programy na wiele klas, często przezornie, na zapas. I to też czasami kończy się chaosem, tylko zamiast mieć chaos w jednej klasie, to masz chaos różnych klas i nic nie robi się bezpośrednio.
Więc i tak źle, i tak nie dobrze.
Jednak to zależy od umiejętności programisty. Jak programista ma skille, to ma więcej wyczucia, kiedy wydzielać klasy i jakie. Wtedy może być podzielone na ładne klasy, gdzie każda klasa robi coś konkretnego. Ale żeby tego się nauczyć zwykle trzeba próbować różnych rzeczy. Jeśli nie jesteś przyzwyczajony do wielu klas, to warto nauczyć się działać w ten sposób. Warto dzielić na klasy, ale trzeba wiedzieć, jak to zrobić i do jakiego stopnia. Ale żeby się tego nauczyć, potrzeba praktyki i umiejętności myślenia abstrakcjami.
Oczywiście jak coś jest małe, to czasem można to napisać po prostu tak o. Można zacząc od pisania wszystkiego w jednym miejscu, a potem dopiero wydzielać klasy. Być może te tutoriale są niepotrzebnie pokomplikowane (bo tak też może być, że proste obliczenia dzielą na ileś klas).
Pytanie typu - czy potrzebny mi więcej niż jeden segregator jak wszystko mogę sobie wrzucić do jednego?
Możesz sobie wszystko wrzucać do jednego miejsca, dopóki się w tym nie gubisz i nie spowalnia ci to pracy to super.
Narzut organizacji jest zazwyczaj mały w porównaniu do porządków które później musisz robić żeby cokolwiek znaleźć.
Dobrze, żeby kod był czytelny, ale bardzo ważny jest też czas tworzenia. Masz do napisania ogromną ilość tekstu jeśli chcesz się czegoś nauczyć, przećwiczyć. Pisz jak najszybciej i staraj się w tym nie pogubić.
Odpowiedź jest bardzo prosta - to zależy
Warto też nabrać pewnej umiejętności wydzielania klas, przerabiania kodu.
Tj. piszesz dużą i wydzielasz potem mniejsze wg funkcjonalności.
Albo odwrotnie - usuwasz niepotrzebne klasy, szczególnie jeśli nic nie robią, a tylko przekazują dane z jednej klasy do drugiej.
Albo przesuwasz odpowiedzialności z jednej klasy do drugiej.
Czyli warto przejść od myślenia jak warto napisać (raz napisać i już)
do traktowania tego w sposób bardziej dynamiczny. To, że kod jest napisany tak i tak, nie znaczy, że nie można go za chwilę zmienić.
Teoretycznie można cały system napisać wyłącznie na metodach statycznych, czyli potraktować Javę jak managed wersję języka C. I wtedy naturalnie można też wszystkie metody przenieść do jednej klasy. Tylko że nawet w języku C ludzie dzielą kod na osobne pliki, bo to jest optymalizacja pod człowieka, który czyta kod.
To, co piszesz, dotyka jeszcze innej kwestii. Mówi się, że Java to język obiektowy, ale często systemy w Javie są pisane w stylu proceduralnym, gdzie klasy pełnią rolę namespace na powiązane ze sobą funkcje. Bardzo rzadko się spotykam z klasą która jest faktycznie zarówno strukturą danych jak i logiką. Np takie obiekty jak Service czy Controller to są obiekty bez stanu i służą jako mechanizm podawania parametrów do funkcji które mogłyby być statyczne w zasadzie. I nie ma w tym nic złego.
Czyli jeśli twój algorytm jest proceduralny lub funkcyjny z natury, a tak mi się wydaje, z tego co piszesz w pierwszym poście, traktuj klasy jak mechanizm podziału na moduły. Nie musisz od razu pakować wszystko w typowe dla Javy patterny typu FooCalculatorFactoryConfiguratorConsumer.
ArchitektSpaghetti napisał(a):
Nie musisz od razu pakować wszystko w typowe dla Javy patterny typu FooCalculatorFactoryConfiguratorConsumer.
Zawsze mnie irytowało określenie, że to są nazwy typowe dla języka. No nie To są nazwy typowe dla ludzi którzy nie rozumieją intencji i wykoślawiają je do takich potworków.
Riddle napisał(a):
ArchitektSpaghetti napisał(a):
Nie musisz od razu pakować wszystko w typowe dla Javy patterny typu FooCalculatorFactoryConfiguratorConsumer.
Zawsze mnie irytowało określenie, że to są nazwy typowe dla języka. No nie To są nazwy typowe dla ludzi którzy nie rozumieją intencji i wykoślawiają je do takich potworków.
Przecież @ArchitektSpaghetti nie chodzi o nazwę, tylko o fakt że nie trzeba od razu stosować wszystkich możliwych patternów obiektowych pisząc w Javie.
Tu macie najpopularniejszy framework w języku Java:
tyle ile trzeba architektura to jak solenie zupy ...
Można używać chatgpt do takich pytań. Rozważ kupienie sobie dobrej książki albo dobrego kursu, który tłumaczy o co chodzi w tym wszystkim, a nie tylko wali przykłady.
Edycja: ponieważ Riddle słusznie zwrócił mi uwagę, że nie mogę podawać odpowiedzi z chatgpt, podaję możliwe zapytanie:
"in java can i make a few computational methods in main class"
@Mokona wklepałem to pytanie to chatagpt: "in java can i make a few computational methods in main class".
Odpowiedzi nie wkleję, jeśli nie wolno, ale powiem tyle, że ona g... daje. Już niektóre posty w tym wątku są sensowniejsze.
"Rozważ kupienie sobie dobrej książki albo dobrego kursu" - co to jest wg Cb dobra książka albo dobry kurs? Czy Clean Code + Clean Architecture + Working Effectively with Legacy Code to byłby wg Cb dobry zestaw na początek?
YetAnohterone napisał(a):
@Mokona wklepałem to pytanie to chatagpt: "in java can i make a few computational methods in main class".
Odpowiedzi nie wkleję, jeśli nie wolno, ale powiem tyle, że ona g... daje. Już niektóre posty w tym wątku są sensowniejsze.
Uważam, że odpowiedź chatgpt wyczerpuje temat zadany przez OPa - chatgpt pokazał że można parę metod mieć w jednej klasie, nie trzeba mieć odzielnych klas do przeprowadzania obliczeń.
Zerkając na historię, trochę inaczej to zrobiłem, może w tym problem, wklepałem 2 komendy
- in java can i make a few methods in main class
Żeby było podobnie jak w przykładach z kursów opa to zrobiłem jeszcze:
- replace the various methods with computational methods
"Rozważ kupienie sobie dobrej książki albo dobrego kursu" - co to jest wg Cb dobra książka albo dobry kurs? Czy Clean Code + Clean Architecture + Working Effectively with Legacy Code to byłby wg Cb dobry zestaw na początek?
Najlepiej taka która tłumaczy przykłady które wprowadza i tłumaczy podstawy - np. co to jest metoda statyczna, czym się to różni od metody, czym się różni obiekt od klasy . Moim zdaniem ten zestaw który wymieniłeś nie pasuje do obecnych potrzeb OPa.
Uważam, że odpowiedź chatgpt wyczerpuje temat zadany przez OPa - chatgpt pokazał że można parę metod mieć w jednej klasie, nie trzeba mieć odzielnych klas do przeprowadzania obliczeń.
No oczywiście że technicznie można, ale co z tego? Przydałoby się raczej napisać, kiedy i dlaczego się tak powinno / nie powinno robić.
Najlepiej taka która tłumaczy przykłady które wprowadza i tłumaczy podstawy - np. co to jest metoda statyczna, czym się to różni od metody, czym się różni obiekt od klasy . Moim zdaniem ten zestaw który wymieniłeś nie pasuje do obecnych potrzeb OPa.
No to poleć lepszy zestaw.
Znowu, napisać o "podręcznikach" bez wskazania których nic nie daje. Sporo jest takich, które piszą bzdury i/lub po prostu rozmijają się z potrzebami OPa.
Paradygmat: obiektowy, proceduralny, funkcyjny, poczytaj trochę o tym, to powinno się rozjaśnić.
Dodatkowo: modularność
efex napisał(a):
Pytanie: czy zamiast tworzyć dodatkowe klasy wraz z metodami nie dałoby się stworzyć kilka metod w głównej klasie main i tylko w odpowiednim momencie kodu wywołać daną metodę żeby zwróciła nam wynik?
Premature optimisation is a root of all evil
Najpierw twórz jak najbardziej granularnie tak żeby pod koniec w ramach refaktoru uwspólniać części które rzeczywiście się do tego nadają. Wiesz skąd się wzięła popularność patternu map-reduce?
Najlepiej pisać dużo własnych projektów i kombinować na wiele sposobów. Robić ten sam rodzaj projektu ileś razy i za każdym trochę inaczej podzielić. Wtedy masz porównanie i widzisz też zalety i wady pewnych rozwiązań.
LukeJL napisał(a):
Najlepiej pisać dużo własnych projektów i kombinować na wiele sposobów. Robić ten sam rodzaj projektu ileś razy i za każdym trochę inaczej podzielić. Wtedy masz porównanie i widzisz też zalety i wady pewnych rozwiązań.
Trzeba też dodać że czasem wady i zalety różnych podejść widać po dłuższym czasie. Sam to po sobie widzę, jak przeglądam stare projekty, że czasem potrzeba nawet roku żeby zauważyć czemu jakieś podejście było słabe.
No i też warto, żeby entuzjazm osiadł. Nagle wpadasz na pomysł, jak można coś zrobić. Albo przeczytasz o wzorcu projektowym. Popatrzysz u kogoś coś. I zaczynasz się tym jarać. I chcesz tego używać, bo np. taki podział klas wiele ci ułatwi. Albo taki podział klas sprawi, że będziesz profesjonalistą (nie tylko o "podział klas" tu chodzi, no ale ten temat jest o dzieleniu na klasy). Albo po prostu chcesz się tego nauczyć, żeby dostać pracę, więc jarasz się chęcią nauki.
A co się okazuje? Np. może się okazać, że faktycznie coś jest użyteczne, ale ma również pewne koszty. Np. coś wymaga dużo więcej kodu do napisania albo jest niewygodne w codziennym używaniu. I już nie takie fajne? Poza tym nawet jeśli pewne wzorce/techniki są użyteczne, to niekoniecznie są niezbędne w rozwiązaniu tego konkretnego problemu, który masz przed sobą. I to czasem się widzi dopiero po pierwszym zachwycie daną techniką. I potem można bardziej świadomie używać czegoś, a nie wciskać na siłę.
Myślę, że pierwsza reakcja (zachwyt, chęć nauki, zaciekawienie) jest naturalna i przydatna (motywuje do nauki), jednak potem trzeba spojrzeć nieco bardziej chłodno. No ale to się okazuje często po iluś miesiącach (czasem latach) stosowania jakiejś techniki (albo też po miesiącach/latach używania jakiejś biblioteki, frameworka, że to jednak nie jest takie super).
YetAnohterone napisał(a):
Uważam, że odpowiedź chatgpt wyczerpuje temat zadany przez OPa - chatgpt pokazał że można parę metod mieć w jednej klasie, nie trzeba mieć odzielnych klas do przeprowadzania obliczeń.
No oczywiście że technicznie można, ale co z tego? Przydałoby się raczej napisać, kiedy i dlaczego się tak powinno / nie powinno robić.
Najlepiej taka która tłumaczy przykłady które wprowadza i tłumaczy podstawy - np. co to jest metoda statyczna, czym się to różni od metody, czym się różni obiekt od klasy . Moim zdaniem ten zestaw który wymieniłeś nie pasuje do obecnych potrzeb OPa.
No to poleć lepszy zestaw.
Znowu, napisać o "podręcznikach" bez wskazania których nic nie daje. Sporo jest takich, które piszą bzdury i/lub po prostu rozmijają się z potrzebami OPa.
Pisanie co mam robić jest imho trochę niewłaściwe(jak i konstruktywna krytyka że moja pomoc "g... daje"). Pomogłem w takim kierunku i na tyle na ile uważałem. Podręczników nie polecę konkretnych, bo uczyłem się wieki temu. Sama uwaga o tym, że z jego kursem może być coś nie tak, bo być może nie wyjaśnia podstaw, jest o tyle pomocna, że można na to nie wpaść na początku. O rekomendację może już dalej sam zapytać, może ktoś inny mu pomoże (np. Ty).
Wskazałem możliwość korzystania z chatgpt żeby zobaczyć czy coś technicznie można zrobić czy nie.
Pomijając moje tłumaczenie do mojej pomocy, naprawdę uważam że są odpowiedniejsze sposoby na zwrócenie komuś uwagi że coś robi nie tak nawet jak tak uważa. Przykładem jest wiadomośc od @Riddle który zwrócił mi uwagę na mój błąd, bez oceniania ani rozkazywania.
@Mokona Racja, przepraszam.
Dałoby się stworzyć kilka metod w klasie main. Osobiście jestem zdania, że to nawet nie powinny być metody, tylko funkcje, ale że Java nie ma funkcji, bo kiedyś tam uznano, że to ma być język obiektowy bez funkcji, to funkcje nazwano metodami statycznymi (metodami klasy).
Dalej, technicznie trzeba taką "klasę" stworzyć, ale pełni ona rolę jedynie organizacji kodu, bo np. możesz chcieć mieć więcej mniejszych kawałków kodu. Zresztą sama Java trzyma swoje metody matematyczne właśnie jako statyczne metody klasy Math,
Kursy on-line używają często mało życiowych przykładów, bo chcą np. pokazać, że można mieć obiekt, do którego przekażesz 2 liczby i możesz wywołać metodę zwracającą ich sumę.
efex napisał(a):
Cześć wszystkim, przepraszam za trochę przewrotne pytanie. Przesiadłem się z dość mało znanego języka MQL4 na Java i czegoś nie rozumiem. Posilę się przykładem. Chciałbym dokonać kilkunastu różnych obliczeń i z tego co widzę na kursach online, wszyscy tworzą oddzielną klasę lub kilka klas do przeprowadzania żądanych obliczeń. W tych klasach znajdują się metody itd. Pytanie: czy zamiast tworzyć dodatkowe klasy wraz z metodami nie dałoby się stworzyć kilka metod w głównej klasie main i tylko w odpowiednim momencie kodu wywołać daną metodę żeby zwróciła nam wynik?
Poczytaj na początek:
- Co to jest programowanie obiektowe
- Po co są przy tym programowaniu klasy
- Po co są metody
- Po co są pola i pola statyczne
- Po co są metody i metody statyczne
- Po co są klasy abstrakcyjne
- Po co są interfejsy
Potem lub w między czasie:
- Clean code
- Wzorce projektowe
Dopiero wtedy zadaj pytanie - o ile w ogóle będziesz jeszcze musiał
W języku obiektowym pisze się dlatego aby łatwiej człowiek mógł sobie zwizualizować i przedstawić, a potem opisać działanie.
Dlatego wymyśla twory które będą reprezentowały problem.
Samochód składa się z kółek, drzwi, silnika, siedzeń, kierownicy.
Do tego dochodzi jak te elementy się do siebie odnoszą - ale to też kolejny temat np. co to jest agregacja.
I tak samochód agreguje koła. De facto każde jest takie samo. Koło agreguje śruby mocujące. Itd.
Ale czy samochód w świecie rzeczywistym istnieje? - Nie. Istnieją dopiero jego implementacje np.: Polonez, Duży Fiat ...
Dlatego też klasa abstrakcyjna to Samochód. A jej implementacja już nieabstrakcyjna to Polonez.
Tak samo jest z kołem.
Samochód agreguje koła - które sam sobie tworzy wewnątrz swojego konstruktora za pomocą:
public class Polonez {
public Polonez() {
for ( int c = 0; c < 4 c++ ) {
new Kolo()
}
}
}
Samochód ma określone zachowania. Np.:
- jedź
- hamuj
- zepsuj się
I to są interfejsy.
public class Samochod implements Hamuj, Jedz, ZepsujSie {
I teraz czy warto tworzyć wszędzie klasy?
Odpowiedź krótka:
- to zależy do jakiego projektu
Dla bardzo małego projektu.. można koncentrować wszystko w małej liczbie klasy.
Odpowiedź prawidłowa:
- raczej tak.
A konkretnie klasa ma zawierać w sobie kod takich metod, który tylko jej dotyczą i nic więcej.
Tak samo jest dla metody - metoda ma realizować tylko i wyłącznie zadanie do którego została stworzona. I absolutnie niczego mniej i niczego więcej robić nie ma prawa.
Dlaczego klasa Math ma w sobie wiele metod i to w dodatku statycznych?
A bo każda z tych metod robi tylko jedno określone działanie. A do jej działania nie jest potrzebne absolutnie nic więcej oprócz przekazanych jej argumentów.
Dlatego te metody są statyczne. Czyli nie tworzysz obiektu na podstawie definicji klasy Math - tylko bezpośrednio, beszczelnie wywołujesz jej metody statyczne.
Inny przykład to wartość liczby Pi która też się tam znajduje (z dokładnością do około 15 miejsc po przecinku) :
System.out.println("Wartość liczby π: " + Math.PI);
A więc jeżeli będziesz u siebie w projekcie chciał sobie w każdej metodzie wyświetlić jakąś wartość w konsoli, to nie musisz tego robić za pomocą:
System.out.println("komunikat");
Tylko sobie stworzysz klasę o nazwie MessagePrinter, w której stworzysz sobie statyczną metodę, która będzie to za ciebie robić w odpowiedni sposób:
import static java.lang.System.out; // Tu celowo użyłem importu statycznego abyś też się z nim zaznajomił i nie musiał wszędzie w kodzie pisać pełnej składni: "System.out.println()"
public class MessagePrinter {
public static void printMessage(String msg) {
out.println(msg);
}
}
Jak widzisz metoda printMessage() jest statyczna, więc używasz ją szybko, zgrabnie i bezboleśnie.
Czyli jak widzisz klasa MessagePrinter realizuje jakieś tam swoje działania.
U ciebie - nie twórz metod obliczeniowych w głównej klasie projektu. Tylko stwórz przynajmniej oddzielną klasę od obliczeń - i tam już sobie te "wszystkie" metody najwyżej umieść. A klasa główna będzie jej używała oraz innych klas które będą przeznaczone do czego innego.
A minusy tworzenia wszędzie klas są takie... że potem jest ich pełno w kodzie. I - niby ciężko - się połapać co jest czym.
Ale jak poczytasz sobie o Clean Code i nabierzesz wprawy z pracą pod IDE - to sam zobaczysz, że nagle ta duża ilość klas przestaje być problemem.
p.s.
Osobiście to nawet staram się tworzyć każdą klasę w oddzielnym pliku
A widywałem już projekty gdzie ilość klas to była znacznie powyżej 10.000. Dzieli się wtedy też projekt na pakiety, moduły itd.
p.s.2
A kiedyś odkryjesz, że zamiast tworzyć własne klasy typu MessagePrinter można używać do tego celu logger'a. I zadasz sobie pytanie: "Czemu ja o tym wcześniej nie wiedziałem?"
Tylko że to nie ma za wiele wspólnego z programowaniem obiektowym W najlepszym wypadku to ogromne uproszczenie dla nie-programistów. Klasa Car
z metodami jedz()
to bajeczka i powód czemu ktoś po usłyszeniu takiej rewelacji zaczyna sądzić że faktyczne OOP się do niczego nie nadaje.
Albo może inaczej.
Programowanie obiektowe dostarcza pewnych konkretnych korzyści; których to co jest zaprezentowane wyżej na pewno nie dostarczy - tak powiem.
OOP jest jak ogry - ma warstwy.
Na poziomie koncepcji moim skromnym zdaniem padło i się nie sprawdziło. W praktyce nie da się efektywnie modelować zewnętrznej rzeczywistości za pomocą klas i obiektów. Przez lata książki od OOP zachwycały się jak to można sobie zrobić ciąg właściwości kot.ogon.kolor
i jak bardzo to ułatwia modelowanie świata. Tylko jak pojawia się realna, skomplikowana domena, to OOD spada z rowerka.
Na warstwie implementacji zależy nam głównie na modularyzacji kodu, hermetyzacji modułów, a w rezultacie na rozbiciu problemu na mniejsze problemiki możliwe do ogarnięcia w całości. Tutaj OOP, czy może "obiekty" się sprawdzają. Bo fajnie mieć np. obiekt reprezentujący jakiś zewnętrzny (mikro) serwis, bazę danych, usługę kolejek itd. Zwolennicy programowania funkcyjnego pewnie mają inne zdanie, ale zdaje się, że języki ewoluują w kierunku obiektowo funkcyjnych hybryd, pozwalających zastosować wygodniejsze podejście w zależności od rozwiązywanego problemu.
Odpowiadam - trzeba zrobić tyle klas żeby nie zwolnili