Jakie są różnice między tymi paradygmatami programowania i czy są one lepiej dostosowane do konkretnych problemów, czy też jakieś przypadki użycia faworyzują jeden nad drugim?
Docenione przykłady architektury!
Jakie są różnice między tymi paradygmatami programowania i czy są one lepiej dostosowane do konkretnych problemów, czy też jakieś przypadki użycia faworyzują jeden nad drugim?
Docenione przykłady architektury!
Odpowiedzi:
Wszyscy są dobrzy na swój sposób - są po prostu innym podejściem do tych samych problemów.
W czysto proceduralnym stylu dane są zwykle bardzo oddzielone od funkcji, które na nich działają.
W stylu obiektowym dane zwykle niosą ze sobą zbiór funkcji.
W stylu funkcjonalnym dane i funkcje mają tendencję do posiadania większej liczby wspólnych elementów (jak w Lisp i Scheme), oferując jednocześnie większą elastyczność pod względem faktycznego wykorzystania funkcji. Algorytmy zwykle definiuje się także w kategoriach rekurencji i kompozycji, a nie pętli i iteracji.
Oczywiście sam język wpływa tylko na preferowany styl. Nawet w czysto funkcjonalnym języku, takim jak Haskell, możesz pisać w stylu proceduralnym (choć jest to bardzo odradzane), a nawet w języku proceduralnym, takim jak C, możesz programować w stylu obiektowym (takim jak GTK + i EFL API).
Mówiąc jasno, „zaletą” każdego paradygmatu jest po prostu modelowanie algorytmów i struktur danych. Jeśli na przykład twój algorytm obejmuje listy i drzewa, algorytm funkcjonalny może być najbardziej sensowny. Lub, na przykład, jeśli twoje dane są wysoce ustrukturyzowane, bardziej sensowne może być skomponowanie ich jako obiektów, jeśli jest to natywny paradygmat twojego języka - lub równie łatwo można je zapisać jako funkcjonalną abstrakcję monad, które jest rodzimym paradygmatem języków takich jak Haskell lub ML.
Wybór, którego używasz, jest po prostu tym, co ma większy sens dla twojego projektu i abstrakcji obsługiwanych przez Twój język.
Myślę, że dostępne biblioteki, narzędzia, przykłady i społeczności całkowicie przebijają paradygmat w dzisiejszych czasach. Na przykład ML (lub cokolwiek innego) może być najlepszym uniwersalnym językiem programowania , ale jeśli nie możesz dostać żadnych dobrych bibliotek do tego, co robisz, to jesteś zepsuty.
Na przykład, jeśli tworzysz grę wideo, w C ++ jest więcej dobrych przykładów kodu i zestawów SDK, więc prawdopodobnie lepiej ci będzie. W przypadku małej aplikacji internetowej istnieje kilka świetnych frameworków Python, PHP i Ruby, które pozwolą ci szybko uruchomić. Java jest doskonałym wyborem dla większych projektów ze względu na sprawdzanie czasu kompilacji oraz bibliotek i platform korporacyjnych.
Kiedyś standardowe biblioteki dla różnych języków były dość małe i łatwe do replikacji - C, C ++, Asembler, ML, LISP, itp. Były dostarczane z podstawami, ale miały tendencję do drobiazgów, jeśli chodzi o standaryzację rzeczy takich jak komunikacja sieciowa, szyfrowanie, grafika, formaty plików danych (w tym XML), nawet podstawowe struktury danych, takie jak zrównoważone drzewa i tabele skrótów, zostały pominięte!
Współczesne języki, takie jak Python, PHP, Ruby i Java, mają teraz o wiele bardziej przyzwoitą bibliotekę standardową i mają wiele dobrych bibliotek stron trzecich, z których można łatwo korzystać, w dużej mierze dzięki przyjęciu przestrzeni nazw, aby biblioteki nie kolidowały ze sobą, oraz wyrzucanie elementów bezużytecznych w celu ustandaryzowania schematów zarządzania pamięcią bibliotek.
Te paradygmaty nie muszą się wzajemnie wykluczać. Jeśli spojrzysz na python, obsługuje on funkcje i klasy, ale jednocześnie wszystko jest przedmiotem, w tym funkcje. Możesz łączyć i dopasowywać styl funkcjonalny / oop / proceduralny w jednym kawałku kodu.
Mam na myśli to, że w językach funkcjonalnych (przynajmniej w Haskell, jedynym, którego studiowałem) nie ma żadnych stwierdzeń! funkcje są dozwolone tylko w jednym wyrażeniu !! ALE funkcje są pierwszorzędnymi obywatelami, możesz przekazać je jako parametry wraz z szeregiem innych umiejętności. Mogą robić potężne rzeczy za pomocą kilku linii kodu.
Podczas gdy w języku proceduralnym, takim jak C, jedynym sposobem na przekazywanie funkcji jest użycie wskaźników funkcji, a samo to nie umożliwia wielu potężnych zadań.
W Pythonie funkcja jest obywatelem pierwszej klasy, ale może zawierać dowolną liczbę instrukcji. Możesz więc mieć funkcję zawierającą kod proceduralny, ale możesz przekazywać go tak jak języki funkcjonalne.
To samo dotyczy OOP. Język taki jak Java nie pozwala pisać procedur / funkcji poza klasą. Jedynym sposobem na przekazanie funkcji jest zawinięcie jej w obiekt implementujący tę funkcję, a następnie przekazanie tego obiektu.
W Pythonie nie masz tego ograniczenia.
W przypadku GUI powiedziałbym, że paradygmat zorientowany obiektowo jest bardzo odpowiedni. Okno jest obiektem, pola tekstowe są obiektami, a także przycisk OK. Z drugiej strony rzeczy takie jak przetwarzanie łańcuchów mogą być wykonywane przy znacznie mniejszym nakładzie pracy, a zatem prostsze dzięki prostemu paradygmatowi proceduralnemu.
Nie sądzę, żeby to była kwestia języka. Możesz pisać funkcjonalnie, proceduralnie lub obiektowo w prawie dowolnym popularnym języku, chociaż w niektórych przypadkach może to wymagać dodatkowego wysiłku.
Aby odpowiedzieć na twoje pytanie, potrzebujemy dwóch elementów:
Lista stylów / wzorów architektury oprogramowania znajduje się w artykule dotyczącym architektury oprogramowania na Wikipeida. Możesz je łatwo badać w Internecie.
W skrócie, Proceduralna jest dobra dla modelu, który postępuje zgodnie z procedurą, OOP jest dobry do projektowania, a Funkcjonalny jest dobry do programowania na wysokim poziomie.
Myślę, że powinieneś spróbować przeczytać historię każdego paradygmatu i przekonać się, dlaczego ludzie ją tworzą, i możesz je łatwo zrozumieć.
Po zrozumieniu ich obu możesz połączyć elementy stylów / wzorców architektury z paradygmatami programowania.
Jeden z moich znajomych pisze aplikację graficzną przy użyciu NVIDIA CUDA . Aplikacja bardzo ładnie wpasowuje się w paradygmat OOP, a problem można starannie rozłożyć na moduły. Jednak aby użyć CUDA, musisz użyć C, który nie obsługuje dziedziczenia . Dlatego musisz być mądry.
a) Opracowujesz sprytny system, który do pewnego stopnia będzie naśladował dziedzictwo. To może być zrobione!
i) Możesz użyć systemu przechwytującego , który oczekuje, że każde dziecko C rodzica P będzie miało pewne przesłonięcie dla funkcji F. Możesz zmusić dzieci do zarejestrowania swoich przesłonięć, które będą przechowywane i wywoływane w razie potrzeby.
ii) Możesz użyć funkcji wyrównania pamięci strukturalnej, aby rzutować dzieci na rodziców.
Może to być fajne, ale nie jest łatwo wymyślić niezawodne rozwiązanie przyszłościowe. Spędzisz dużo czasu na projektowaniu systemu i nie ma gwarancji, że nie napotkasz problemów w połowie projektu. Wdrożenie wielokrotnego dziedziczenia jest jeszcze trudniejsze, jeśli nie prawie niemożliwe.
b) Możesz użyć spójnej polityki nazewnictwa i zastosować podejście dziel i zwyciężaj, aby stworzyć program. Nie będzie dziedziczył, ale ponieważ twoje funkcje są małe, łatwe do zrozumienia i konsekwentnie sformatowane, nie potrzebujesz go. Ilość kodu, który musisz napisać, rośnie, bardzo trudno jest skoncentrować się i nie ulec łatwym rozwiązaniom (włamaniom). Jednak ten sposób kodowania ninja jest sposobem kodowania C. Zachowanie równowagi między swobodą niskiego poziomu a pisaniem dobrego kodu. Dobrym sposobem na osiągnięcie tego jest pisanie prototypów za pomocą funkcjonalnego języka. Na przykład Haskell jest wyjątkowo dobry do algorytmów prototypowania.
Skłaniam się ku podejściu b. Napisałem możliwe rozwiązanie, stosując podejście a, i powiem szczerze, używanie tego kodu było bardzo nienaturalne.